diff --git a/dumb/vc6/dumb_static/dumb_static.vcproj b/dumb/vc6/dumb_static/dumb_static.vcproj
index 497fe4a997..6d67362598 100644
--- a/dumb/vc6/dumb_static/dumb_static.vcproj
+++ b/dumb/vc6/dumb_static/dumb_static.vcproj
@@ -1203,10 +1203,6 @@
/>
-
-
> 3] & (0x80 >> ((i) & 7))) != 0)
+
+#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
typedef struct
{
- UInt64 *PackSizes;
- Byte *PackCRCsDefined;
- UInt32 *PackCRCs;
- CSzFolder *Folders;
- CSzFileItem *Files;
UInt32 NumPackStreams;
UInt32 NumFolders;
- UInt32 NumFiles;
+
+ UInt64 *PackPositions; // NumPackStreams + 1
+ CSzBitUi32s FolderCRCs; // NumFolders
+
+ size_t *FoCodersOffsets; // NumFolders + 1
+ UInt32 *FoStartPackStreamIndex; // NumFolders + 1
+ UInt32 *FoToCoderUnpackSizes; // NumFolders + 1
+ Byte *FoToMainUnpackSizeIndex; // NumFolders
+ UInt64 *CoderUnpackSizes; // for all coders in all folders
+
+ Byte *CodersData;
} CSzAr;
-void SzAr_Init(CSzAr *p);
-void SzAr_Free(CSzAr *p, ISzAlloc *alloc);
+UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex);
+
+SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
+ ILookInStream *stream, UInt64 startPos,
+ Byte *outBuffer, size_t outSize,
+ ISzAlloc *allocMain);
+
+typedef struct
+{
+ CSzAr db;
+
+ UInt64 startPosAfterHeader;
+ UInt64 dataPos;
+
+ UInt32 NumFiles;
+
+ UInt64 *UnpackPositions; // NumFiles + 1
+ // Byte *IsEmptyFiles;
+ Byte *IsDirs;
+ CSzBitUi32s CRCs;
+
+ CSzBitUi32s Attribs;
+ // CSzBitUi32s Parents;
+ CSzBitUi64s MTime;
+ CSzBitUi64s CTime;
+
+ UInt32 *FolderToFile; // NumFolders + 1
+ UInt32 *FileToFolder; // NumFiles
+
+ size_t *FileNameOffsets; /* in 2-byte steps */
+ Byte *FileNames; /* UTF-16-LE */
+} CSzArEx;
+
+#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i))
+
+#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i])
+
+void SzArEx_Init(CSzArEx *p);
+void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc);
+UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder);
+int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize);
+
+/*
+if dest == NULL, the return value specifies the required size of the buffer,
+ in 16-bit characters, including the null-terminating character.
+if dest != NULL, the return value specifies the number of 16-bit characters that
+ are written to the dest, including the null-terminating character. */
+
+size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
+
+/*
+size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex);
+UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
+*/
+
/*
- SzExtract extracts file from archive
+ SzArEx_Extract extracts file from archive
*outBuffer must be 0 before first call for each new archive.
@@ -143,35 +170,6 @@ void SzAr_Free(CSzAr *p, ISzAlloc *alloc);
Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
*/
-typedef struct
-{
- CSzAr db;
-
- UInt64 startPosAfterHeader;
- UInt64 dataPos;
-
- UInt32 *FolderStartPackStreamIndex;
- UInt64 *PackStreamStartPositions;
- UInt32 *FolderStartFileIndex;
- UInt32 *FileIndexToFolderIndexMap;
-
- size_t *FileNameOffsets; /* in 2-byte steps */
- CBuf FileNames; /* UTF-16-LE */
-} CSzArEx;
-
-void SzArEx_Init(CSzArEx *p);
-void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc);
-UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder);
-int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize);
-
-/*
-if dest == NULL, the return value specifies the required size of the buffer,
- in 16-bit characters, including the null-terminating character.
-if dest != NULL, the return value specifies the number of 16-bit characters that
- are written to the dest, including the null-terminating character. */
-
-size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
-
SRes SzArEx_Extract(
const CSzArEx *db,
ILookInStream *inStream,
@@ -196,7 +194,8 @@ SZ_ERROR_INPUT_EOF
SZ_ERROR_FAIL
*/
-SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp);
+SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream,
+ ISzAlloc *allocMain, ISzAlloc *allocTemp);
EXTERN_C_END
diff --git a/lzma/C/7zArcIn.c b/lzma/C/7zArcIn.c
new file mode 100644
index 0000000000..080d8df2ae
--- /dev/null
+++ b/lzma/C/7zArcIn.c
@@ -0,0 +1,1770 @@
+/* 7zArcIn.c -- 7z Input functions
+2015-11-18 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include
+
+#include "7z.h"
+#include "7zBuf.h"
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+#define MY_ALLOC(T, p, size, alloc) { \
+ if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; }
+
+#define MY_ALLOC_ZE(T, p, size, alloc) { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) }
+
+#define MY_ALLOC_AND_CPY(to, size, from, alloc) \
+ { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); }
+
+#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \
+ { if ((size) == 0) p = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } }
+
+#define k7zMajorVersion 0
+
+enum EIdEnum
+{
+ k7zIdEnd,
+ k7zIdHeader,
+ k7zIdArchiveProperties,
+ k7zIdAdditionalStreamsInfo,
+ k7zIdMainStreamsInfo,
+ k7zIdFilesInfo,
+ k7zIdPackInfo,
+ k7zIdUnpackInfo,
+ k7zIdSubStreamsInfo,
+ k7zIdSize,
+ k7zIdCRC,
+ k7zIdFolder,
+ k7zIdCodersUnpackSize,
+ k7zIdNumUnpackStream,
+ k7zIdEmptyStream,
+ k7zIdEmptyFile,
+ k7zIdAnti,
+ k7zIdName,
+ k7zIdCTime,
+ k7zIdATime,
+ k7zIdMTime,
+ k7zIdWinAttrib,
+ k7zIdComment,
+ k7zIdEncodedHeader,
+ k7zIdStartPos,
+ k7zIdDummy
+ // k7zNtSecure,
+ // k7zParent,
+ // k7zIsReal
+};
+
+const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+#define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; }
+
+static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAlloc *alloc)
+{
+ if (num == 0)
+ {
+ p->Defs = NULL;
+ p->Vals = NULL;
+ }
+ else
+ {
+ MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc);
+ MY_ALLOC(UInt32, p->Vals, num, alloc);
+ }
+ return SZ_OK;
+}
+
+void SzBitUi32s_Free(CSzBitUi32s *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->Defs); p->Defs = NULL;
+ IAlloc_Free(alloc, p->Vals); p->Vals = NULL;
+}
+
+#define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; }
+
+void SzBitUi64s_Free(CSzBitUi64s *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->Defs); p->Defs = NULL;
+ IAlloc_Free(alloc, p->Vals); p->Vals = NULL;
+}
+
+
+static void SzAr_Init(CSzAr *p)
+{
+ p->NumPackStreams = 0;
+ p->NumFolders = 0;
+
+ p->PackPositions = NULL;
+ SzBitUi32s_Init(&p->FolderCRCs);
+
+ p->FoCodersOffsets = NULL;
+ p->FoStartPackStreamIndex = NULL;
+ p->FoToCoderUnpackSizes = NULL;
+ p->FoToMainUnpackSizeIndex = NULL;
+ p->CoderUnpackSizes = NULL;
+
+ p->CodersData = NULL;
+}
+
+static void SzAr_Free(CSzAr *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->PackPositions);
+ SzBitUi32s_Free(&p->FolderCRCs, alloc);
+
+ IAlloc_Free(alloc, p->FoCodersOffsets);
+ IAlloc_Free(alloc, p->FoStartPackStreamIndex);
+ IAlloc_Free(alloc, p->FoToCoderUnpackSizes);
+ IAlloc_Free(alloc, p->FoToMainUnpackSizeIndex);
+ IAlloc_Free(alloc, p->CoderUnpackSizes);
+
+ IAlloc_Free(alloc, p->CodersData);
+
+ SzAr_Init(p);
+}
+
+
+void SzArEx_Init(CSzArEx *p)
+{
+ SzAr_Init(&p->db);
+
+ p->NumFiles = 0;
+ p->dataPos = 0;
+
+ p->UnpackPositions = NULL;
+ p->IsDirs = NULL;
+
+ p->FolderToFile = NULL;
+ p->FileToFolder = NULL;
+
+ p->FileNameOffsets = NULL;
+ p->FileNames = NULL;
+
+ SzBitUi32s_Init(&p->CRCs);
+ SzBitUi32s_Init(&p->Attribs);
+ // SzBitUi32s_Init(&p->Parents);
+ SzBitUi64s_Init(&p->MTime);
+ SzBitUi64s_Init(&p->CTime);
+}
+
+void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->UnpackPositions);
+ IAlloc_Free(alloc, p->IsDirs);
+
+ IAlloc_Free(alloc, p->FolderToFile);
+ IAlloc_Free(alloc, p->FileToFolder);
+
+ IAlloc_Free(alloc, p->FileNameOffsets);
+ IAlloc_Free(alloc, p->FileNames);
+
+ SzBitUi32s_Free(&p->CRCs, alloc);
+ SzBitUi32s_Free(&p->Attribs, alloc);
+ // SzBitUi32s_Free(&p->Parents, alloc);
+ SzBitUi64s_Free(&p->MTime, alloc);
+ SzBitUi64s_Free(&p->CTime, alloc);
+
+ SzAr_Free(&p->db, alloc);
+ SzArEx_Init(p);
+}
+
+
+static int TestSignatureCandidate(const Byte *testBytes)
+{
+ unsigned i;
+ for (i = 0; i < k7zSignatureSize; i++)
+ if (testBytes[i] != k7zSignature[i])
+ return 0;
+ return 1;
+}
+
+#define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; }
+
+#define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++;
+#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest)
+#define SZ_READ_BYTE_2(dest) if (sd.Size == 0) return SZ_ERROR_ARCHIVE; sd.Size--; dest = *sd.Data++;
+
+#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); }
+#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); }
+
+#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \
+ dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4);
+
+static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value)
+{
+ Byte firstByte, mask;
+ unsigned i;
+ UInt32 v;
+
+ SZ_READ_BYTE(firstByte);
+ if ((firstByte & 0x80) == 0)
+ {
+ *value = firstByte;
+ return SZ_OK;
+ }
+ SZ_READ_BYTE(v);
+ if ((firstByte & 0x40) == 0)
+ {
+ *value = (((UInt32)firstByte & 0x3F) << 8) | v;
+ return SZ_OK;
+ }
+ SZ_READ_BYTE(mask);
+ *value = v | ((UInt32)mask << 8);
+ mask = 0x20;
+ for (i = 2; i < 8; i++)
+ {
+ Byte b;
+ if ((firstByte & mask) == 0)
+ {
+ UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1);
+ *value |= (highPart << (8 * i));
+ return SZ_OK;
+ }
+ SZ_READ_BYTE(b);
+ *value |= ((UInt64)b << (8 * i));
+ mask >>= 1;
+ }
+ return SZ_OK;
+}
+
+
+static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value)
+{
+ Byte firstByte;
+ UInt64 value64;
+ if (sd->Size == 0)
+ return SZ_ERROR_ARCHIVE;
+ firstByte = *sd->Data;
+ if ((firstByte & 0x80) == 0)
+ {
+ *value = firstByte;
+ sd->Data++;
+ sd->Size--;
+ return SZ_OK;
+ }
+ RINOK(ReadNumber(sd, &value64));
+ if (value64 >= (UInt32)0x80000000 - 1)
+ return SZ_ERROR_UNSUPPORTED;
+ if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4)))
+ return SZ_ERROR_UNSUPPORTED;
+ *value = (UInt32)value64;
+ return SZ_OK;
+}
+
+#define ReadID(sd, value) ReadNumber(sd, value)
+
+static SRes SkipData(CSzData *sd)
+{
+ UInt64 size;
+ RINOK(ReadNumber(sd, &size));
+ if (size > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA(sd, size);
+ return SZ_OK;
+}
+
+static SRes WaitId(CSzData *sd, UInt32 id)
+{
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(sd, &type));
+ if (type == id)
+ return SZ_OK;
+ if (type == k7zIdEnd)
+ return SZ_ERROR_ARCHIVE;
+ RINOK(SkipData(sd));
+ }
+}
+
+static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v)
+{
+ UInt32 numBytes = (numItems + 7) >> 3;
+ if (numBytes > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ *v = sd->Data;
+ SKIP_DATA(sd, numBytes);
+ return SZ_OK;
+}
+
+static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems)
+{
+ Byte b = 0;
+ unsigned m = 0;
+ UInt32 sum = 0;
+ for (; numItems != 0; numItems--)
+ {
+ if (m == 0)
+ {
+ b = *bits++;
+ m = 8;
+ }
+ m--;
+ sum += ((b >> m) & 1);
+ }
+ return sum;
+}
+
+static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAlloc *alloc)
+{
+ Byte allAreDefined;
+ Byte *v2;
+ UInt32 numBytes = (numItems + 7) >> 3;
+ *v = NULL;
+ SZ_READ_BYTE(allAreDefined);
+ if (numBytes == 0)
+ return SZ_OK;
+ if (allAreDefined == 0)
+ {
+ if (numBytes > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc);
+ SKIP_DATA(sd, numBytes);
+ return SZ_OK;
+ }
+ MY_ALLOC(Byte, *v, numBytes, alloc);
+ v2 = *v;
+ memset(v2, 0xFF, (size_t)numBytes);
+ {
+ unsigned numBits = (unsigned)numItems & 7;
+ if (numBits != 0)
+ v2[numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits));
+ }
+ return SZ_OK;
+}
+
+static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc)
+{
+ UInt32 i;
+ CSzData sd;
+ UInt32 *vals;
+ const Byte *defs;
+ MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc);
+ sd = *sd2;
+ defs = crcs->Defs;
+ vals = crcs->Vals;
+ for (i = 0; i < numItems; i++)
+ if (SzBitArray_Check(defs, i))
+ {
+ SZ_READ_32(vals[i]);
+ }
+ else
+ vals[i] = 0;
+ *sd2 = sd;
+ return SZ_OK;
+}
+
+static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc)
+{
+ SzBitUi32s_Free(crcs, alloc);
+ RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc));
+ return ReadUi32s(sd, numItems, crcs, alloc);
+}
+
+static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems)
+{
+ Byte allAreDefined;
+ UInt32 numDefined = numItems;
+ SZ_READ_BYTE(allAreDefined);
+ if (!allAreDefined)
+ {
+ size_t numBytes = (numItems + 7) >> 3;
+ if (numBytes > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ numDefined = CountDefinedBits(sd->Data, numItems);
+ SKIP_DATA(sd, numBytes);
+ }
+ if (numDefined > (sd->Size >> 2))
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA(sd, (size_t)numDefined * 4);
+ return SZ_OK;
+}
+
+static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAlloc *alloc)
+{
+ RINOK(SzReadNumber32(sd, &p->NumPackStreams));
+
+ RINOK(WaitId(sd, k7zIdSize));
+ MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc);
+ {
+ UInt64 sum = 0;
+ UInt32 i;
+ UInt32 numPackStreams = p->NumPackStreams;
+ for (i = 0; i < numPackStreams; i++)
+ {
+ UInt64 packSize;
+ p->PackPositions[i] = sum;
+ RINOK(ReadNumber(sd, &packSize));
+ sum += packSize;
+ if (sum < packSize)
+ return SZ_ERROR_ARCHIVE;
+ }
+ p->PackPositions[i] = sum;
+ }
+
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdEnd)
+ return SZ_OK;
+ if (type == k7zIdCRC)
+ {
+ /* CRC of packed streams is unused now */
+ RINOK(SkipBitUi32s(sd, p->NumPackStreams));
+ continue;
+ }
+ RINOK(SkipData(sd));
+ }
+}
+
+/*
+static SRes SzReadSwitch(CSzData *sd)
+{
+ Byte external;
+ RINOK(SzReadByte(sd, &external));
+ return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
+}
+*/
+
+#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
+
+SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd)
+{
+ UInt32 numCoders, i;
+ UInt32 numInStreams = 0;
+ const Byte *dataStart = sd->Data;
+
+ f->NumCoders = 0;
+ f->NumBonds = 0;
+ f->NumPackStreams = 0;
+ f->UnpackStream = 0;
+
+ RINOK(SzReadNumber32(sd, &numCoders));
+ if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (i = 0; i < numCoders; i++)
+ {
+ Byte mainByte;
+ CSzCoderInfo *coder = f->Coders + i;
+ unsigned idSize, j;
+ UInt64 id;
+
+ SZ_READ_BYTE(mainByte);
+ if ((mainByte & 0xC0) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+
+ idSize = (unsigned)(mainByte & 0xF);
+ if (idSize > sizeof(id))
+ return SZ_ERROR_UNSUPPORTED;
+ if (idSize > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ id = 0;
+ for (j = 0; j < idSize; j++)
+ {
+ id = ((id << 8) | *sd->Data);
+ sd->Data++;
+ sd->Size--;
+ }
+ if (id > (UInt32)0xFFFFFFFF)
+ return SZ_ERROR_UNSUPPORTED;
+ coder->MethodID = (UInt32)id;
+
+ coder->NumStreams = 1;
+ coder->PropsOffset = 0;
+ coder->PropsSize = 0;
+
+ if ((mainByte & 0x10) != 0)
+ {
+ UInt32 numStreams;
+
+ RINOK(SzReadNumber32(sd, &numStreams));
+ if (numStreams > k_NumCodersStreams_in_Folder_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ coder->NumStreams = (Byte)numStreams;
+
+ RINOK(SzReadNumber32(sd, &numStreams));
+ if (numStreams != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+
+ numInStreams += coder->NumStreams;
+
+ if (numInStreams > k_NumCodersStreams_in_Folder_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ if ((mainByte & 0x20) != 0)
+ {
+ UInt32 propsSize = 0;
+ RINOK(SzReadNumber32(sd, &propsSize));
+ if (propsSize > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ if (propsSize >= 0x80)
+ return SZ_ERROR_UNSUPPORTED;
+ coder->PropsOffset = sd->Data - dataStart;
+ coder->PropsSize = (Byte)propsSize;
+ sd->Data += (size_t)propsSize;
+ sd->Size -= (size_t)propsSize;
+ }
+ }
+
+ /*
+ if (numInStreams == 1 && numCoders == 1)
+ {
+ f->NumPackStreams = 1;
+ f->PackStreams[0] = 0;
+ }
+ else
+ */
+ {
+ Byte streamUsed[k_NumCodersStreams_in_Folder_MAX];
+ UInt32 numBonds, numPackStreams;
+
+ numBonds = numCoders - 1;
+ if (numInStreams < numBonds)
+ return SZ_ERROR_ARCHIVE;
+ if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ f->NumBonds = numBonds;
+
+ numPackStreams = numInStreams - numBonds;
+ if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ f->NumPackStreams = numPackStreams;
+
+ for (i = 0; i < numInStreams; i++)
+ streamUsed[i] = False;
+
+ if (numBonds != 0)
+ {
+ Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX];
+
+ for (i = 0; i < numCoders; i++)
+ coderUsed[i] = False;
+
+ for (i = 0; i < numBonds; i++)
+ {
+ CSzBond *bp = f->Bonds + i;
+
+ RINOK(SzReadNumber32(sd, &bp->InIndex));
+ if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[bp->InIndex] = True;
+
+ RINOK(SzReadNumber32(sd, &bp->OutIndex));
+ if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex])
+ return SZ_ERROR_ARCHIVE;
+ coderUsed[bp->OutIndex] = True;
+ }
+
+ for (i = 0; i < numCoders; i++)
+ if (!coderUsed[i])
+ {
+ f->UnpackStream = i;
+ break;
+ }
+
+ if (i == numCoders)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ if (numPackStreams == 1)
+ {
+ for (i = 0; i < numInStreams; i++)
+ if (!streamUsed[i])
+ break;
+ if (i == numInStreams)
+ return SZ_ERROR_ARCHIVE;
+ f->PackStreams[0] = i;
+ }
+ else
+ for (i = 0; i < numPackStreams; i++)
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd, &index));
+ if (index >= numInStreams || streamUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[index] = True;
+ f->PackStreams[i] = index;
+ }
+ }
+
+ f->NumCoders = numCoders;
+
+ return SZ_OK;
+}
+
+
+static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num)
+{
+ CSzData sd;
+ sd = *sd2;
+ for (; num != 0; num--)
+ {
+ Byte firstByte, mask;
+ unsigned i;
+ SZ_READ_BYTE_2(firstByte);
+ if ((firstByte & 0x80) == 0)
+ continue;
+ if ((firstByte & 0x40) == 0)
+ {
+ if (sd.Size == 0)
+ return SZ_ERROR_ARCHIVE;
+ sd.Size--;
+ sd.Data++;
+ continue;
+ }
+ mask = 0x20;
+ for (i = 2; i < 8 && (firstByte & mask) != 0; i++)
+ mask >>= 1;
+ if (i > sd.Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA2(sd, i);
+ }
+ *sd2 = sd;
+ return SZ_OK;
+}
+
+
+#define k_Scan_NumCoders_MAX 64
+#define k_Scan_NumCodersStreams_in_Folder_MAX 64
+
+
+static SRes ReadUnpackInfo(CSzAr *p,
+ CSzData *sd2,
+ UInt32 numFoldersMax,
+ const CBuf *tempBufs, UInt32 numTempBufs,
+ ISzAlloc *alloc)
+{
+ CSzData sd;
+
+ UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex;
+ const Byte *startBufPtr;
+ Byte external;
+
+ RINOK(WaitId(sd2, k7zIdFolder));
+
+ RINOK(SzReadNumber32(sd2, &numFolders));
+ if (numFolders > numFoldersMax)
+ return SZ_ERROR_UNSUPPORTED;
+ p->NumFolders = numFolders;
+
+ SZ_READ_BYTE_SD(sd2, external);
+ if (external == 0)
+ sd = *sd2;
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd2, &index));
+ if (index >= numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ sd.Data = tempBufs[index].data;
+ sd.Size = tempBufs[index].size;
+ }
+
+ MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc);
+ MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc);
+ MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc);
+ MY_ALLOC(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc);
+
+ startBufPtr = sd.Data;
+
+ packStreamIndex = 0;
+ numCodersOutStreams = 0;
+
+ for (fo = 0; fo < numFolders; fo++)
+ {
+ UInt32 numCoders, ci, numInStreams = 0;
+
+ p->FoCodersOffsets[fo] = sd.Data - startBufPtr;
+
+ RINOK(SzReadNumber32(&sd, &numCoders));
+ if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (ci = 0; ci < numCoders; ci++)
+ {
+ Byte mainByte;
+ unsigned idSize;
+ UInt32 coderInStreams;
+
+ SZ_READ_BYTE_2(mainByte);
+ if ((mainByte & 0xC0) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ idSize = (mainByte & 0xF);
+ if (idSize > 8)
+ return SZ_ERROR_UNSUPPORTED;
+ if (idSize > sd.Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA2(sd, idSize);
+
+ coderInStreams = 1;
+
+ if ((mainByte & 0x10) != 0)
+ {
+ UInt32 coderOutStreams;
+ RINOK(SzReadNumber32(&sd, &coderInStreams));
+ RINOK(SzReadNumber32(&sd, &coderOutStreams));
+ if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+
+ numInStreams += coderInStreams;
+
+ if ((mainByte & 0x20) != 0)
+ {
+ UInt32 propsSize;
+ RINOK(SzReadNumber32(&sd, &propsSize));
+ if (propsSize > sd.Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA2(sd, propsSize);
+ }
+ }
+
+ {
+ UInt32 indexOfMainStream = 0;
+ UInt32 numPackStreams = 1;
+
+ if (numCoders != 1 || numInStreams != 1)
+ {
+ Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX];
+ Byte coderUsed[k_Scan_NumCoders_MAX];
+
+ UInt32 i;
+ UInt32 numBonds = numCoders - 1;
+ if (numInStreams < numBonds)
+ return SZ_ERROR_ARCHIVE;
+
+ if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (i = 0; i < numInStreams; i++)
+ streamUsed[i] = False;
+ for (i = 0; i < numCoders; i++)
+ coderUsed[i] = False;
+
+ for (i = 0; i < numBonds; i++)
+ {
+ UInt32 index;
+
+ RINOK(SzReadNumber32(&sd, &index));
+ if (index >= numInStreams || streamUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[index] = True;
+
+ RINOK(SzReadNumber32(&sd, &index));
+ if (index >= numCoders || coderUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ coderUsed[index] = True;
+ }
+
+ numPackStreams = numInStreams - numBonds;
+
+ if (numPackStreams != 1)
+ for (i = 0; i < numPackStreams; i++)
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(&sd, &index));
+ if (index >= numInStreams || streamUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[index] = True;
+ }
+
+ for (i = 0; i < numCoders; i++)
+ if (!coderUsed[i])
+ {
+ indexOfMainStream = i;
+ break;
+ }
+
+ if (i == numCoders)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ p->FoStartPackStreamIndex[fo] = packStreamIndex;
+ p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+ p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream;
+ numCodersOutStreams += numCoders;
+ if (numCodersOutStreams < numCoders)
+ return SZ_ERROR_UNSUPPORTED;
+
+ packStreamIndex += numPackStreams;
+ if (packStreamIndex < numPackStreams)
+ return SZ_ERROR_UNSUPPORTED;
+
+ if (packStreamIndex > p->NumPackStreams)
+ return SZ_ERROR_ARCHIVE;
+ }
+ }
+
+ p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+
+ {
+ size_t dataSize = sd.Data - startBufPtr;
+ p->FoStartPackStreamIndex[fo] = packStreamIndex;
+ p->FoCodersOffsets[fo] = dataSize;
+ MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc);
+ }
+
+ if (external != 0)
+ {
+ if (sd.Size != 0)
+ return SZ_ERROR_ARCHIVE;
+ sd = *sd2;
+ }
+
+ RINOK(WaitId(&sd, k7zIdCodersUnpackSize));
+
+ MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc);
+ {
+ UInt32 i;
+ for (i = 0; i < numCodersOutStreams; i++)
+ {
+ RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i));
+ }
+ }
+
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(&sd, &type));
+ if (type == k7zIdEnd)
+ {
+ *sd2 = sd;
+ return SZ_OK;
+ }
+ if (type == k7zIdCRC)
+ {
+ RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc));
+ continue;
+ }
+ RINOK(SkipData(&sd));
+ }
+}
+
+
+UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex)
+{
+ return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]];
+}
+
+
+typedef struct
+{
+ UInt32 NumTotalSubStreams;
+ UInt32 NumSubDigests;
+ CSzData sdNumSubStreams;
+ CSzData sdSizes;
+ CSzData sdCRCs;
+} CSubStreamInfo;
+
+
+static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi)
+{
+ UInt64 type = 0;
+ UInt32 numSubDigests = 0;
+ UInt32 numFolders = p->NumFolders;
+ UInt32 numUnpackStreams = numFolders;
+ UInt32 numUnpackSizesInData = 0;
+
+ for (;;)
+ {
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdNumUnpackStream)
+ {
+ UInt32 i;
+ ssi->sdNumSubStreams.Data = sd->Data;
+ numUnpackStreams = 0;
+ numSubDigests = 0;
+ for (i = 0; i < numFolders; i++)
+ {
+ UInt32 numStreams;
+ RINOK(SzReadNumber32(sd, &numStreams));
+ if (numUnpackStreams > numUnpackStreams + numStreams)
+ return SZ_ERROR_UNSUPPORTED;
+ numUnpackStreams += numStreams;
+ if (numStreams != 0)
+ numUnpackSizesInData += (numStreams - 1);
+ if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i))
+ numSubDigests += numStreams;
+ }
+ ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data;
+ continue;
+ }
+ if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd)
+ break;
+ RINOK(SkipData(sd));
+ }
+
+ if (!ssi->sdNumSubStreams.Data)
+ {
+ numSubDigests = numFolders;
+ if (p->FolderCRCs.Defs)
+ numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders);
+ }
+
+ ssi->NumTotalSubStreams = numUnpackStreams;
+ ssi->NumSubDigests = numSubDigests;
+
+ if (type == k7zIdSize)
+ {
+ ssi->sdSizes.Data = sd->Data;
+ RINOK(SkipNumbers(sd, numUnpackSizesInData));
+ ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data;
+ RINOK(ReadID(sd, &type));
+ }
+
+ for (;;)
+ {
+ if (type == k7zIdEnd)
+ return SZ_OK;
+ if (type == k7zIdCRC)
+ {
+ ssi->sdCRCs.Data = sd->Data;
+ RINOK(SkipBitUi32s(sd, numSubDigests));
+ ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data;
+ }
+ else
+ {
+ RINOK(SkipData(sd));
+ }
+ RINOK(ReadID(sd, &type));
+ }
+}
+
+static SRes SzReadStreamsInfo(CSzAr *p,
+ CSzData *sd,
+ UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs,
+ UInt64 *dataOffset,
+ CSubStreamInfo *ssi,
+ ISzAlloc *alloc)
+{
+ UInt64 type;
+
+ SzData_Clear(&ssi->sdSizes);
+ SzData_Clear(&ssi->sdCRCs);
+ SzData_Clear(&ssi->sdNumSubStreams);
+
+ *dataOffset = 0;
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdPackInfo)
+ {
+ RINOK(ReadNumber(sd, dataOffset));
+ RINOK(ReadPackInfo(p, sd, alloc));
+ RINOK(ReadID(sd, &type));
+ }
+ if (type == k7zIdUnpackInfo)
+ {
+ RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc));
+ RINOK(ReadID(sd, &type));
+ }
+ if (type == k7zIdSubStreamsInfo)
+ {
+ RINOK(ReadSubStreamsInfo(p, sd, ssi));
+ RINOK(ReadID(sd, &type));
+ }
+ else
+ {
+ ssi->NumTotalSubStreams = p->NumFolders;
+ // ssi->NumSubDigests = 0;
+ }
+
+ return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED);
+}
+
+static SRes SzReadAndDecodePackedStreams(
+ ILookInStream *inStream,
+ CSzData *sd,
+ CBuf *tempBufs,
+ UInt32 numFoldersMax,
+ UInt64 baseOffset,
+ CSzAr *p,
+ ISzAlloc *allocTemp)
+{
+ UInt64 dataStartPos;
+ UInt32 fo;
+ CSubStreamInfo ssi;
+
+ RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp));
+
+ dataStartPos += baseOffset;
+ if (p->NumFolders == 0)
+ return SZ_ERROR_ARCHIVE;
+
+ for (fo = 0; fo < p->NumFolders; fo++)
+ Buf_Init(tempBufs + fo);
+
+ for (fo = 0; fo < p->NumFolders; fo++)
+ {
+ CBuf *tempBuf = tempBufs + fo;
+ UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo);
+ if ((size_t)unpackSize != unpackSize)
+ return SZ_ERROR_MEM;
+ if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp))
+ return SZ_ERROR_MEM;
+ }
+
+ for (fo = 0; fo < p->NumFolders; fo++)
+ {
+ const CBuf *tempBuf = tempBufs + fo;
+ RINOK(LookInStream_SeekTo(inStream, dataStartPos));
+ RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp));
+ }
+
+ return SZ_OK;
+}
+
+static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets)
+{
+ size_t pos = 0;
+ *offsets++ = 0;
+ if (numFiles == 0)
+ return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE;
+ if (size < 2)
+ return SZ_ERROR_ARCHIVE;
+ if (data[size - 2] != 0 || data[size - 1] != 0)
+ return SZ_ERROR_ARCHIVE;
+ do
+ {
+ const Byte *p;
+ if (pos == size)
+ return SZ_ERROR_ARCHIVE;
+ for (p = data + pos;
+ #ifdef _WIN32
+ *(const UInt16 *)p != 0
+ #else
+ p[0] != 0 || p[1] != 0
+ #endif
+ ; p += 2);
+ pos = p - data + 2;
+ *offsets++ = (pos >> 1);
+ }
+ while (--numFiles);
+ return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
+}
+
+static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num,
+ CSzData *sd2,
+ const CBuf *tempBufs, UInt32 numTempBufs,
+ ISzAlloc *alloc)
+{
+ CSzData sd;
+ UInt32 i;
+ CNtfsFileTime *vals;
+ Byte *defs;
+ Byte external;
+
+ RINOK(ReadBitVector(sd2, num, &p->Defs, alloc));
+
+ SZ_READ_BYTE_SD(sd2, external);
+ if (external == 0)
+ sd = *sd2;
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd2, &index));
+ if (index >= numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ sd.Data = tempBufs[index].data;
+ sd.Size = tempBufs[index].size;
+ }
+
+ MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc);
+ vals = p->Vals;
+ defs = p->Defs;
+ for (i = 0; i < num; i++)
+ if (SzBitArray_Check(defs, i))
+ {
+ if (sd.Size < 8)
+ return SZ_ERROR_ARCHIVE;
+ vals[i].Low = GetUi32(sd.Data);
+ vals[i].High = GetUi32(sd.Data + 4);
+ SKIP_DATA2(sd, 8);
+ }
+ else
+ vals[i].High = vals[i].Low = 0;
+
+ if (external == 0)
+ *sd2 = sd;
+
+ return SZ_OK;
+}
+
+
+#define NUM_ADDITIONAL_STREAMS_MAX 8
+
+
+static SRes SzReadHeader2(
+ CSzArEx *p, /* allocMain */
+ CSzData *sd,
+ ILookInStream *inStream,
+ CBuf *tempBufs, UInt32 *numTempBufs,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp
+ )
+{
+ UInt64 type;
+ UInt32 numFiles = 0;
+ UInt32 numEmptyStreams = 0;
+ CSubStreamInfo ssi;
+ const Byte *emptyStreams = NULL;
+ const Byte *emptyFiles = NULL;
+
+ SzData_Clear(&ssi.sdSizes);
+ SzData_Clear(&ssi.sdCRCs);
+ SzData_Clear(&ssi.sdNumSubStreams);
+
+ ssi.NumSubDigests = 0;
+ ssi.NumTotalSubStreams = 0;
+
+ RINOK(ReadID(sd, &type));
+
+ if (type == k7zIdArchiveProperties)
+ {
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ RINOK(SkipData(sd));
+ }
+ RINOK(ReadID(sd, &type));
+ }
+
+ if (type == k7zIdAdditionalStreamsInfo)
+ {
+ CSzAr tempAr;
+ SRes res;
+
+ SzAr_Init(&tempAr);
+ res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX,
+ p->startPosAfterHeader, &tempAr, allocTemp);
+ *numTempBufs = tempAr.NumFolders;
+ SzAr_Free(&tempAr, allocTemp);
+
+ if (res != SZ_OK)
+ return res;
+ RINOK(ReadID(sd, &type));
+ }
+
+ if (type == k7zIdMainStreamsInfo)
+ {
+ RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs,
+ &p->dataPos, &ssi, allocMain));
+ p->dataPos += p->startPosAfterHeader;
+ RINOK(ReadID(sd, &type));
+ }
+
+ if (type == k7zIdEnd)
+ {
+ return SZ_OK;
+ }
+
+ if (type != k7zIdFilesInfo)
+ return SZ_ERROR_ARCHIVE;
+
+ RINOK(SzReadNumber32(sd, &numFiles));
+ p->NumFiles = numFiles;
+
+ for (;;)
+ {
+ UInt64 type;
+ UInt64 size;
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ RINOK(ReadNumber(sd, &size));
+ if (size > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+
+ if (type >= ((UInt32)1 << 8))
+ {
+ SKIP_DATA(sd, size);
+ }
+ else switch ((unsigned)type)
+ {
+ case k7zIdName:
+ {
+ size_t namesSize;
+ const Byte *namesData;
+ Byte external;
+
+ SZ_READ_BYTE(external);
+ if (external == 0)
+ {
+ namesSize = (size_t)size - 1;
+ namesData = sd->Data;
+ }
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd, &index));
+ if (index >= *numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ namesData = (tempBufs)[index].data;
+ namesSize = (tempBufs)[index].size;
+ }
+
+ if ((namesSize & 1) != 0)
+ return SZ_ERROR_ARCHIVE;
+ MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain);
+ MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain);
+ RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets))
+ if (external == 0)
+ {
+ SKIP_DATA(sd, namesSize);
+ }
+ break;
+ }
+ case k7zIdEmptyStream:
+ {
+ RINOK(RememberBitVector(sd, numFiles, &emptyStreams));
+ numEmptyStreams = CountDefinedBits(emptyStreams, numFiles);
+ emptyFiles = NULL;
+ break;
+ }
+ case k7zIdEmptyFile:
+ {
+ RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles));
+ break;
+ }
+ case k7zIdWinAttrib:
+ {
+ Byte external;
+ CSzData sdSwitch;
+ CSzData *sdPtr;
+ SzBitUi32s_Free(&p->Attribs, allocMain);
+ RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain));
+
+ SZ_READ_BYTE(external);
+ if (external == 0)
+ sdPtr = sd;
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd, &index));
+ if (index >= *numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ sdSwitch.Data = (tempBufs)[index].data;
+ sdSwitch.Size = (tempBufs)[index].size;
+ sdPtr = &sdSwitch;
+ }
+ RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain));
+ break;
+ }
+ /*
+ case k7zParent:
+ {
+ SzBitUi32s_Free(&p->Parents, allocMain);
+ RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain));
+ RINOK(SzReadSwitch(sd));
+ RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain));
+ break;
+ }
+ */
+ case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break;
+ case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break;
+ default:
+ {
+ SKIP_DATA(sd, size);
+ }
+ }
+ }
+
+ if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams)
+ return SZ_ERROR_ARCHIVE;
+
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ RINOK(SkipData(sd));
+ }
+
+ {
+ UInt32 i;
+ UInt32 emptyFileIndex = 0;
+ UInt32 folderIndex = 0;
+ UInt32 remSubStreams = 0;
+ UInt32 numSubStreams = 0;
+ UInt64 unpackPos = 0;
+ const Byte *digestsDefs = NULL;
+ const Byte *digestsVals = NULL;
+ UInt32 digestsValsIndex = 0;
+ UInt32 digestIndex;
+ Byte allDigestsDefined = 0;
+ Byte isDirMask = 0;
+ Byte crcMask = 0;
+ Byte mask = 0x80;
+
+ MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain);
+ MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain);
+ MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain);
+ MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain);
+
+ RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain));
+
+ if (ssi.sdCRCs.Size != 0)
+ {
+ SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined);
+ if (allDigestsDefined)
+ digestsVals = ssi.sdCRCs.Data;
+ else
+ {
+ size_t numBytes = (ssi.NumSubDigests + 7) >> 3;
+ digestsDefs = ssi.sdCRCs.Data;
+ digestsVals = digestsDefs + numBytes;
+ }
+ }
+
+ digestIndex = 0;
+
+ for (i = 0; i < numFiles; i++, mask >>= 1)
+ {
+ if (mask == 0)
+ {
+ UInt32 byteIndex = (i - 1) >> 3;
+ p->IsDirs[byteIndex] = isDirMask;
+ p->CRCs.Defs[byteIndex] = crcMask;
+ isDirMask = 0;
+ crcMask = 0;
+ mask = 0x80;
+ }
+
+ p->UnpackPositions[i] = unpackPos;
+ p->CRCs.Vals[i] = 0;
+
+ if (emptyStreams && SzBitArray_Check(emptyStreams, i))
+ {
+ if (emptyFiles)
+ {
+ if (!SzBitArray_Check(emptyFiles, emptyFileIndex))
+ isDirMask |= mask;
+ emptyFileIndex++;
+ }
+ else
+ isDirMask |= mask;
+ if (remSubStreams == 0)
+ {
+ p->FileToFolder[i] = (UInt32)-1;
+ continue;
+ }
+ }
+
+ if (remSubStreams == 0)
+ {
+ for (;;)
+ {
+ if (folderIndex >= p->db.NumFolders)
+ return SZ_ERROR_ARCHIVE;
+ p->FolderToFile[folderIndex] = i;
+ numSubStreams = 1;
+ if (ssi.sdNumSubStreams.Data)
+ {
+ RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams));
+ }
+ remSubStreams = numSubStreams;
+ if (numSubStreams != 0)
+ break;
+ {
+ UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ unpackPos += folderUnpackSize;
+ if (unpackPos < folderUnpackSize)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ folderIndex++;
+ }
+ }
+
+ p->FileToFolder[i] = folderIndex;
+
+ if (emptyStreams && SzBitArray_Check(emptyStreams, i))
+ continue;
+
+ if (--remSubStreams == 0)
+ {
+ UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]];
+ if (folderUnpackSize < unpackPos - startFolderUnpackPos)
+ return SZ_ERROR_ARCHIVE;
+ unpackPos = startFolderUnpackPos + folderUnpackSize;
+ if (unpackPos < folderUnpackSize)
+ return SZ_ERROR_ARCHIVE;
+
+ if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i))
+ {
+ p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex];
+ crcMask |= mask;
+ }
+ else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))
+ {
+ p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);
+ digestsValsIndex++;
+ crcMask |= mask;
+ }
+
+ folderIndex++;
+ }
+ else
+ {
+ UInt64 v;
+ RINOK(ReadNumber(&ssi.sdSizes, &v));
+ unpackPos += v;
+ if (unpackPos < v)
+ return SZ_ERROR_ARCHIVE;
+ if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))
+ {
+ p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);
+ digestsValsIndex++;
+ crcMask |= mask;
+ }
+ }
+ }
+
+ if (mask != 0x80)
+ {
+ UInt32 byteIndex = (i - 1) >> 3;
+ p->IsDirs[byteIndex] = isDirMask;
+ p->CRCs.Defs[byteIndex] = crcMask;
+ }
+
+ p->UnpackPositions[i] = unpackPos;
+
+ if (remSubStreams != 0)
+ return SZ_ERROR_ARCHIVE;
+
+ for (;;)
+ {
+ p->FolderToFile[folderIndex] = i;
+ if (folderIndex >= p->db.NumFolders)
+ break;
+ if (!ssi.sdNumSubStreams.Data)
+ return SZ_ERROR_ARCHIVE;
+ RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams));
+ if (numSubStreams != 0)
+ return SZ_ERROR_ARCHIVE;
+ /*
+ {
+ UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ unpackPos += folderUnpackSize;
+ if (unpackPos < folderUnpackSize)
+ return SZ_ERROR_ARCHIVE;
+ }
+ */
+ folderIndex++;
+ }
+
+ if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ return SZ_OK;
+}
+
+
+static SRes SzReadHeader(
+ CSzArEx *p,
+ CSzData *sd,
+ ILookInStream *inStream,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ UInt32 i;
+ UInt32 numTempBufs = 0;
+ SRes res;
+ CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX];
+
+ for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)
+ Buf_Init(tempBufs + i);
+
+ res = SzReadHeader2(p, sd, inStream,
+ tempBufs, &numTempBufs,
+ allocMain, allocTemp);
+
+ for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)
+ Buf_Free(tempBufs + i, allocTemp);
+
+ RINOK(res);
+
+ if (sd->Size != 0)
+ return SZ_ERROR_FAIL;
+
+ return res;
+}
+
+static SRes SzArEx_Open2(
+ CSzArEx *p,
+ ILookInStream *inStream,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ Byte header[k7zStartHeaderSize];
+ Int64 startArcPos;
+ UInt64 nextHeaderOffset, nextHeaderSize;
+ size_t nextHeaderSizeT;
+ UInt32 nextHeaderCRC;
+ CBuf buf;
+ SRes res;
+
+ startArcPos = 0;
+ RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR));
+
+ RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));
+
+ if (!TestSignatureCandidate(header))
+ return SZ_ERROR_NO_ARCHIVE;
+ if (header[6] != k7zMajorVersion)
+ return SZ_ERROR_UNSUPPORTED;
+
+ nextHeaderOffset = GetUi64(header + 12);
+ nextHeaderSize = GetUi64(header + 20);
+ nextHeaderCRC = GetUi32(header + 28);
+
+ p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;
+
+ if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
+ return SZ_ERROR_CRC;
+
+ nextHeaderSizeT = (size_t)nextHeaderSize;
+ if (nextHeaderSizeT != nextHeaderSize)
+ return SZ_ERROR_MEM;
+ if (nextHeaderSizeT == 0)
+ return SZ_OK;
+ if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize ||
+ nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize)
+ return SZ_ERROR_NO_ARCHIVE;
+
+ {
+ Int64 pos = 0;
+ RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END));
+ if ((UInt64)pos < startArcPos + nextHeaderOffset ||
+ (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
+ (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
+ return SZ_ERROR_INPUT_EOF;
+ }
+
+ RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));
+
+ if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp))
+ return SZ_ERROR_MEM;
+
+ res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT);
+
+ if (res == SZ_OK)
+ {
+ res = SZ_ERROR_ARCHIVE;
+ if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC)
+ {
+ CSzData sd;
+ UInt64 type;
+ sd.Data = buf.data;
+ sd.Size = buf.size;
+
+ res = ReadID(&sd, &type);
+
+ if (res == SZ_OK && type == k7zIdEncodedHeader)
+ {
+ CSzAr tempAr;
+ CBuf tempBuf;
+ Buf_Init(&tempBuf);
+
+ SzAr_Init(&tempAr);
+ res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp);
+ SzAr_Free(&tempAr, allocTemp);
+
+ if (res != SZ_OK)
+ {
+ Buf_Free(&tempBuf, allocTemp);
+ }
+ else
+ {
+ Buf_Free(&buf, allocTemp);
+ buf.data = tempBuf.data;
+ buf.size = tempBuf.size;
+ sd.Data = buf.data;
+ sd.Size = buf.size;
+ res = ReadID(&sd, &type);
+ }
+ }
+
+ if (res == SZ_OK)
+ {
+ if (type == k7zIdHeader)
+ {
+ /*
+ CSzData sd2;
+ unsigned ttt;
+ for (ttt = 0; ttt < 40000; ttt++)
+ {
+ SzArEx_Free(p, allocMain);
+ sd2 = sd;
+ res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp);
+ if (res != SZ_OK)
+ break;
+ }
+ */
+ res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp);
+ }
+ else
+ res = SZ_ERROR_UNSUPPORTED;
+ }
+ }
+ }
+
+ Buf_Free(&buf, allocTemp);
+ return res;
+}
+
+
+SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream,
+ ISzAlloc *allocMain, ISzAlloc *allocTemp)
+{
+ SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
+ if (res != SZ_OK)
+ SzArEx_Free(p, allocMain);
+ return res;
+}
+
+
+SRes SzArEx_Extract(
+ const CSzArEx *p,
+ ILookInStream *inStream,
+ UInt32 fileIndex,
+ UInt32 *blockIndex,
+ Byte **tempBuf,
+ size_t *outBufferSize,
+ size_t *offset,
+ size_t *outSizeProcessed,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ UInt32 folderIndex = p->FileToFolder[fileIndex];
+ SRes res = SZ_OK;
+
+ *offset = 0;
+ *outSizeProcessed = 0;
+
+ if (folderIndex == (UInt32)-1)
+ {
+ IAlloc_Free(allocMain, *tempBuf);
+ *blockIndex = folderIndex;
+ *tempBuf = NULL;
+ *outBufferSize = 0;
+ return SZ_OK;
+ }
+
+ if (*tempBuf == NULL || *blockIndex != folderIndex)
+ {
+ UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ /*
+ UInt64 unpackSizeSpec =
+ p->UnpackPositions[p->FolderToFile[folderIndex + 1]] -
+ p->UnpackPositions[p->FolderToFile[folderIndex]];
+ */
+ size_t unpackSize = (size_t)unpackSizeSpec;
+
+ if (unpackSize != unpackSizeSpec)
+ return SZ_ERROR_MEM;
+ *blockIndex = folderIndex;
+ IAlloc_Free(allocMain, *tempBuf);
+ *tempBuf = NULL;
+
+ if (res == SZ_OK)
+ {
+ *outBufferSize = unpackSize;
+ if (unpackSize != 0)
+ {
+ *tempBuf = (Byte *)IAlloc_Alloc(allocMain, unpackSize);
+ if (*tempBuf == NULL)
+ res = SZ_ERROR_MEM;
+ }
+
+ if (res == SZ_OK)
+ {
+ res = SzAr_DecodeFolder(&p->db, folderIndex,
+ inStream, p->dataPos, *tempBuf, unpackSize, allocTemp);
+ }
+ }
+ }
+
+ if (res == SZ_OK)
+ {
+ UInt64 unpackPos = p->UnpackPositions[fileIndex];
+ *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]);
+ *outSizeProcessed = (size_t)(p->UnpackPositions[fileIndex + 1] - unpackPos);
+ if (*offset + *outSizeProcessed > *outBufferSize)
+ return SZ_ERROR_FAIL;
+ if (SzBitWithVals_Check(&p->CRCs, fileIndex))
+ if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex])
+ res = SZ_ERROR_CRC;
+ }
+
+ return res;
+}
+
+
+size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
+{
+ size_t offs = p->FileNameOffsets[fileIndex];
+ size_t len = p->FileNameOffsets[fileIndex + 1] - offs;
+ if (dest != 0)
+ {
+ size_t i;
+ const Byte *src = p->FileNames + offs * 2;
+ for (i = 0; i < len; i++)
+ dest[i] = GetUi16(src + i * 2);
+ }
+ return len;
+}
+
+/*
+size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex)
+{
+ size_t len;
+ if (!p->FileNameOffsets)
+ return 1;
+ len = 0;
+ for (;;)
+ {
+ UInt32 parent = (UInt32)(Int32)-1;
+ len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
+ if SzBitWithVals_Check(&p->Parents, fileIndex)
+ parent = p->Parents.Vals[fileIndex];
+ if (parent == (UInt32)(Int32)-1)
+ return len;
+ fileIndex = parent;
+ }
+}
+
+UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
+{
+ Bool needSlash;
+ if (!p->FileNameOffsets)
+ {
+ *(--dest) = 0;
+ return dest;
+ }
+ needSlash = False;
+ for (;;)
+ {
+ UInt32 parent = (UInt32)(Int32)-1;
+ size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
+ SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen);
+ if (needSlash)
+ *(dest - 1) = '/';
+ needSlash = True;
+ dest -= curLen;
+
+ if SzBitWithVals_Check(&p->Parents, fileIndex)
+ parent = p->Parents.Vals[fileIndex];
+ if (parent == (UInt32)(Int32)-1)
+ return dest;
+ fileIndex = parent;
+ }
+}
+*/
diff --git a/lzma/C/7zBuf.c b/lzma/C/7zBuf.c
index a35fa2f988..b0ac1104b9 100644
--- a/lzma/C/7zBuf.c
+++ b/lzma/C/7zBuf.c
@@ -1,7 +1,7 @@
/* 7zBuf.c -- Byte Buffer
-2008-03-28
-Igor Pavlov
-Public domain */
+2013-01-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include "7zBuf.h"
diff --git a/lzma/C/7zBuf.h b/lzma/C/7zBuf.h
index 88ff0c2f2d..e5f9218bed 100644
--- a/lzma/C/7zBuf.h
+++ b/lzma/C/7zBuf.h
@@ -1,14 +1,12 @@
/* 7zBuf.h -- Byte Buffer
-2009-02-07 : Igor Pavlov : Public domain */
+2013-01-18 : Igor Pavlov : Public domain */
#ifndef __7Z_BUF_H
#define __7Z_BUF_H
-#include "Types.h"
+#include "7zTypes.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
+EXTERN_C_BEGIN
typedef struct
{
@@ -32,8 +30,6 @@ void DynBuf_SeekToBeg(CDynBuf *p);
int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc);
void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc);
-#ifdef __cplusplus
-}
-#endif
+EXTERN_C_END
#endif
diff --git a/lzma/C/7zCrc.c b/lzma/C/7zCrc.c
index 6993a69884..607db34041 100644
--- a/lzma/C/7zCrc.c
+++ b/lzma/C/7zCrc.c
@@ -1,29 +1,35 @@
/* 7zCrc.c -- CRC32 init
-2010-12-01 : Igor Pavlov : Public domain */
+2015-03-10 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include "7zCrc.h"
#include "CpuArch.h"
#define kCrcPoly 0xEDB88320
-#ifdef MY_CPU_X86_OR_AMD64
+#ifdef MY_CPU_LE
#define CRC_NUM_TABLES 8
- UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
-#elif defined(MY_CPU_LE)
- #define CRC_NUM_TABLES 4
#else
- #define CRC_NUM_TABLES 5
+ #define CRC_NUM_TABLES 9
+
#define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24))
+
UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+ UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
#endif
#ifndef MY_CPU_BE
UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+ UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
#endif
typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
-static CRC_FUNC g_CrcUpdate;
+CRC_FUNC g_CrcUpdateT4;
+CRC_FUNC g_CrcUpdateT8;
+CRC_FUNC g_CrcUpdate;
+
UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
@@ -36,6 +42,17 @@ UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
}
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ const Byte *pEnd = p + size;
+ for (; p != pEnd; p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
void MY_FAST_CALL CrcGenerateTable()
{
UInt32 i;
@@ -52,22 +69,43 @@ void MY_FAST_CALL CrcGenerateTable()
UInt32 r = g_CrcTable[i - 256];
g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
}
+
+ #if CRC_NUM_TABLES < 4
+ g_CrcUpdate = CrcUpdateT1;
+
+ #else
+
#ifdef MY_CPU_LE
- g_CrcUpdate = CrcUpdateT4;
+ g_CrcUpdateT4 = CrcUpdateT4;
+ g_CrcUpdate = CrcUpdateT4;
+
+ #if CRC_NUM_TABLES >= 8
+ g_CrcUpdateT8 = CrcUpdateT8;
- #if CRC_NUM_TABLES == 8
- if (!CPU_Is_InOrder())
- g_CrcUpdate = CrcUpdateT8;
- #endif
+ #ifdef MY_CPU_X86_OR_AMD64
+ if (!CPU_Is_InOrder())
+ g_CrcUpdate = CrcUpdateT8;
+ #endif
+ #endif
#else
{
#ifndef MY_CPU_BE
- UInt32 k = 1;
- if (*(const Byte *)&k == 1)
+ UInt32 k = 0x01020304;
+ const Byte *p = (const Byte *)&k;
+ if (p[0] == 4 && p[1] == 3)
+ {
+ g_CrcUpdateT4 = CrcUpdateT4;
g_CrcUpdate = CrcUpdateT4;
+ #if CRC_NUM_TABLES >= 8
+ g_CrcUpdateT8 = CrcUpdateT8;
+ // g_CrcUpdate = CrcUpdateT8;
+ #endif
+ }
+ else if (p[0] != 1 || p[1] != 2)
+ g_CrcUpdate = CrcUpdateT1;
else
#endif
{
@@ -76,8 +114,15 @@ void MY_FAST_CALL CrcGenerateTable()
UInt32 x = g_CrcTable[i - 256];
g_CrcTable[i] = CRC_UINT32_SWAP(x);
}
+ g_CrcUpdateT4 = CrcUpdateT1_BeT4;
g_CrcUpdate = CrcUpdateT1_BeT4;
+ #if CRC_NUM_TABLES >= 8
+ g_CrcUpdateT8 = CrcUpdateT1_BeT8;
+ // g_CrcUpdate = CrcUpdateT1_BeT8;
+ #endif
}
}
#endif
+
+ #endif
}
diff --git a/lzma/C/7zCrc.h b/lzma/C/7zCrc.h
index 4a1ec38c93..3b0459402b 100644
--- a/lzma/C/7zCrc.h
+++ b/lzma/C/7zCrc.h
@@ -1,10 +1,10 @@
/* 7zCrc.h -- CRC32 calculation
-2009-11-21 : Igor Pavlov : Public domain */
+2013-01-18 : Igor Pavlov : Public domain */
#ifndef __7Z_CRC_H
#define __7Z_CRC_H
-#include "Types.h"
+#include "7zTypes.h"
EXTERN_C_BEGIN
diff --git a/lzma/C/7zCrcOpt.c b/lzma/C/7zCrcOpt.c
index 85405ccfc1..58628efe56 100644
--- a/lzma/C/7zCrcOpt.c
+++ b/lzma/C/7zCrcOpt.c
@@ -1,12 +1,14 @@
/* 7zCrcOpt.c -- CRC32 calculation
-2010-12-01 : Igor Pavlov : Public domain */
+2015-03-01 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include "CpuArch.h"
-#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
-
#ifndef MY_CPU_BE
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
{
const Byte *p = (const Byte *)data;
@@ -16,10 +18,10 @@ UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const U
{
v ^= *(const UInt32 *)p;
v =
- table[0x300 + (v & 0xFF)] ^
- table[0x200 + ((v >> 8) & 0xFF)] ^
- table[0x100 + ((v >> 16) & 0xFF)] ^
- table[0x000 + ((v >> 24))];
+ table[0x300 + ((v ) & 0xFF)]
+ ^ table[0x200 + ((v >> 8) & 0xFF)]
+ ^ table[0x100 + ((v >> 16) & 0xFF)]
+ ^ table[0x000 + ((v >> 24))];
}
for (; size > 0; size--, p++)
v = CRC_UPDATE_BYTE_2(v, *p);
@@ -28,7 +30,28 @@ UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const U
UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
{
- return CrcUpdateT4(v, data, size, table);
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ for (; size >= 8; size -= 8, p += 8)
+ {
+ UInt32 d;
+ v ^= *(const UInt32 *)p;
+ v =
+ table[0x700 + ((v ) & 0xFF)]
+ ^ table[0x600 + ((v >> 8) & 0xFF)]
+ ^ table[0x500 + ((v >> 16) & 0xFF)]
+ ^ table[0x400 + ((v >> 24))];
+ d = *((const UInt32 *)p + 1);
+ v ^=
+ table[0x300 + ((d ) & 0xFF)]
+ ^ table[0x200 + ((d >> 8) & 0xFF)]
+ ^ table[0x100 + ((d >> 16) & 0xFF)]
+ ^ table[0x000 + ((d >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
}
#endif
@@ -38,27 +61,55 @@ UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const U
#define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24))
+#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8))
+
UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
{
const Byte *p = (const Byte *)data;
- for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
- v = CRC_UPDATE_BYTE_2(v, *p);
- v = CRC_UINT32_SWAP(v);
table += 0x100;
+ v = CRC_UINT32_SWAP(v);
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
for (; size >= 4; size -= 4, p += 4)
{
v ^= *(const UInt32 *)p;
v =
- table[0x000 + (v & 0xFF)] ^
- table[0x100 + ((v >> 8) & 0xFF)] ^
- table[0x200 + ((v >> 16) & 0xFF)] ^
- table[0x300 + ((v >> 24))];
+ table[0x000 + ((v ) & 0xFF)]
+ ^ table[0x100 + ((v >> 8) & 0xFF)]
+ ^ table[0x200 + ((v >> 16) & 0xFF)]
+ ^ table[0x300 + ((v >> 24))];
}
- table -= 0x100;
- v = CRC_UINT32_SWAP(v);
for (; size > 0; size--, p++)
- v = CRC_UPDATE_BYTE_2(v, *p);
- return v;
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
+ return CRC_UINT32_SWAP(v);
+}
+
+UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ table += 0x100;
+ v = CRC_UINT32_SWAP(v);
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
+ for (; size >= 8; size -= 8, p += 8)
+ {
+ UInt32 d;
+ v ^= *(const UInt32 *)p;
+ v =
+ table[0x400 + ((v ) & 0xFF)]
+ ^ table[0x500 + ((v >> 8) & 0xFF)]
+ ^ table[0x600 + ((v >> 16) & 0xFF)]
+ ^ table[0x700 + ((v >> 24))];
+ d = *((const UInt32 *)p + 1);
+ v ^=
+ table[0x000 + ((d ) & 0xFF)]
+ ^ table[0x100 + ((d >> 8) & 0xFF)]
+ ^ table[0x200 + ((d >> 16) & 0xFF)]
+ ^ table[0x300 + ((d >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
+ return CRC_UINT32_SWAP(v);
}
#endif
diff --git a/lzma/C/7zDec.c b/lzma/C/7zDec.c
index 338680747c..e39b4ff12a 100644
--- a/lzma/C/7zDec.c
+++ b/lzma/C/7zDec.c
@@ -1,15 +1,19 @@
/* 7zDec.c -- Decoding from 7z folder
-2010-11-02 : Igor Pavlov : Public domain */
+2015-11-18 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include
/* #define _7ZIP_PPMD_SUPPPORT */
#include "7z.h"
+#include "7zCrc.h"
#include "Bcj2.h"
#include "Bra.h"
#include "CpuArch.h"
+#include "Delta.h"
#include "LzmaDec.h"
#include "Lzma2Dec.h"
#ifdef _7ZIP_PPMD_SUPPPORT
@@ -17,14 +21,17 @@
#endif
#define k_Copy 0
+#define k_Delta 3
#define k_LZMA2 0x21
#define k_LZMA 0x30101
-#define k_BCJ 0x03030103
-#define k_PPC 0x03030205
-#define k_ARM 0x03030501
-#define k_ARMT 0x03030701
-#define k_SPARC 0x03030805
-#define k_BCJ2 0x0303011B
+#define k_BCJ 0x3030103
+#define k_BCJ2 0x303011B
+#define k_PPC 0x3030205
+#define k_IA64 0x3030401
+#define k_ARM 0x3030501
+#define k_ARMT 0x3030701
+#define k_SPARC 0x3030805
+
#ifdef _7ZIP_PPMD_SUPPPORT
@@ -63,7 +70,7 @@ static Byte ReadByte(void *pp)
return 0;
}
-static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
+static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
{
CPpmd7 ppmd;
@@ -77,12 +84,12 @@ static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt
s.res = SZ_OK;
s.processed = 0;
- if (coder->Props.size != 5)
+ if (propsSize != 5)
return SZ_ERROR_UNSUPPORTED;
{
- unsigned order = coder->Props.data[0];
- UInt32 memSize = GetUi32(coder->Props.data + 1);
+ unsigned order = props[0];
+ UInt32 memSize = GetUi32(props + 1);
if (order < PPMD7_MIN_ORDER ||
order > PPMD7_MAX_ORDER ||
memSize < PPMD7_MIN_MEM_SIZE ||
@@ -124,25 +131,25 @@ static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt
#endif
-static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
+static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
{
CLzmaDec state;
SRes res = SZ_OK;
LzmaDec_Construct(&state);
- RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain));
+ RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain));
state.dic = outBuffer;
state.dicBufSize = outSize;
LzmaDec_Init(&state);
for (;;)
{
- Byte *inBuf = NULL;
+ const void *inBuf = NULL;
size_t lookahead = (1 << 18);
if (lookahead > inSize)
lookahead = (size_t)inSize;
- res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
+ res = inStream->Look(inStream, &inBuf, &lookahead);
if (res != SZ_OK)
break;
@@ -154,14 +161,23 @@ static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt
inSize -= inProcessed;
if (res != SZ_OK)
break;
- if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
+
+ if (status == LZMA_STATUS_FINISHED_WITH_MARK)
{
- if (state.dicBufSize != outSize || lookahead != 0 ||
- (status != LZMA_STATUS_FINISHED_WITH_MARK &&
- status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
+ if (outSize != state.dicPos || inSize != 0)
res = SZ_ERROR_DATA;
break;
}
+
+ if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ break;
+
+ if (inProcessed == 0 && dicPos == state.dicPos)
+ {
+ res = SZ_ERROR_DATA;
+ break;
+ }
+
res = inStream->Skip((void *)inStream, inProcessed);
if (res != SZ_OK)
break;
@@ -172,27 +188,30 @@ static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt
return res;
}
-static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
+
+#ifndef _7Z_NO_METHOD_LZMA2
+
+static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
{
CLzma2Dec state;
SRes res = SZ_OK;
Lzma2Dec_Construct(&state);
- if (coder->Props.size != 1)
+ if (propsSize != 1)
return SZ_ERROR_DATA;
- RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain));
+ RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain));
state.decoder.dic = outBuffer;
state.decoder.dicBufSize = outSize;
Lzma2Dec_Init(&state);
for (;;)
{
- Byte *inBuf = NULL;
+ const void *inBuf = NULL;
size_t lookahead = (1 << 18);
if (lookahead > inSize)
lookahead = (size_t)inSize;
- res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
+ res = inStream->Look(inStream, &inBuf, &lookahead);
if (res != SZ_OK)
break;
@@ -204,13 +223,20 @@ static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inS
inSize -= inProcessed;
if (res != SZ_OK)
break;
- if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
+
+ if (status == LZMA_STATUS_FINISHED_WITH_MARK)
{
- if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
- (status != LZMA_STATUS_FINISHED_WITH_MARK))
+ if (outSize != state.decoder.dicPos || inSize != 0)
res = SZ_ERROR_DATA;
break;
}
+
+ if (inProcessed == 0 && dicPos == state.decoder.dicPos)
+ {
+ res = SZ_ERROR_DATA;
+ break;
+ }
+
res = inStream->Skip((void *)inStream, inProcessed);
if (res != SZ_OK)
break;
@@ -221,15 +247,18 @@ static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inS
return res;
}
+#endif
+
+
static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
{
while (inSize > 0)
{
- void *inBuf;
+ const void *inBuf;
size_t curSize = (1 << 18);
if (curSize > inSize)
curSize = (size_t)inSize;
- RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize));
+ RINOK(inStream->Look(inStream, &inBuf, &curSize));
if (curSize == 0)
return SZ_ERROR_INPUT_EOF;
memcpy(outBuffer, inBuf, curSize);
@@ -242,11 +271,13 @@ static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer
static Bool IS_MAIN_METHOD(UInt32 m)
{
- switch(m)
+ switch (m)
{
case k_Copy:
case k_LZMA:
+ #ifndef _7Z_NO_METHOD_LZMA2
case k_LZMA2:
+ #endif
#ifdef _7ZIP_PPMD_SUPPPORT
case k_PPMD:
#endif
@@ -258,13 +289,12 @@ static Bool IS_MAIN_METHOD(UInt32 m)
static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
{
return
- c->NumInStreams == 1 &&
- c->NumOutStreams == 1 &&
- c->MethodID <= (UInt32)0xFFFFFFFF &&
- IS_MAIN_METHOD((UInt32)c->MethodID);
+ c->NumStreams == 1
+ /* && c->MethodID <= (UInt32)0xFFFFFFFF */
+ && IS_MAIN_METHOD((UInt32)c->MethodID);
}
-#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
+#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
static SRes CheckSupportedFolder(const CSzFolder *f)
{
@@ -274,65 +304,73 @@ static SRes CheckSupportedFolder(const CSzFolder *f)
return SZ_ERROR_UNSUPPORTED;
if (f->NumCoders == 1)
{
- if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
+ if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
return SZ_ERROR_UNSUPPORTED;
return SZ_OK;
}
+
+
+ #ifndef _7Z_NO_METHODS_FILTERS
+
if (f->NumCoders == 2)
{
- CSzCoderInfo *c = &f->Coders[1];
- if (c->MethodID > (UInt32)0xFFFFFFFF ||
- c->NumInStreams != 1 ||
- c->NumOutStreams != 1 ||
- f->NumPackStreams != 1 ||
- f->PackStreams[0] != 0 ||
- f->NumBindPairs != 1 ||
- f->BindPairs[0].InIndex != 1 ||
- f->BindPairs[0].OutIndex != 0)
+ const CSzCoderInfo *c = &f->Coders[1];
+ if (
+ /* c->MethodID > (UInt32)0xFFFFFFFF || */
+ c->NumStreams != 1
+ || f->NumPackStreams != 1
+ || f->PackStreams[0] != 0
+ || f->NumBonds != 1
+ || f->Bonds[0].InIndex != 1
+ || f->Bonds[0].OutIndex != 0)
return SZ_ERROR_UNSUPPORTED;
switch ((UInt32)c->MethodID)
{
+ case k_Delta:
case k_BCJ:
+ case k_PPC:
+ case k_IA64:
+ case k_SPARC:
case k_ARM:
+ case k_ARMT:
break;
default:
return SZ_ERROR_UNSUPPORTED;
}
return SZ_OK;
}
+
+ #endif
+
+
if (f->NumCoders == 4)
{
- if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
- !IS_SUPPORTED_CODER(&f->Coders[2]) ||
- !IS_BCJ2(&f->Coders[3]))
+ if (!IS_SUPPORTED_CODER(&f->Coders[1])
+ || !IS_SUPPORTED_CODER(&f->Coders[2])
+ || !IS_BCJ2(&f->Coders[3]))
return SZ_ERROR_UNSUPPORTED;
- if (f->NumPackStreams != 4 ||
- f->PackStreams[0] != 2 ||
- f->PackStreams[1] != 6 ||
- f->PackStreams[2] != 1 ||
- f->PackStreams[3] != 0 ||
- f->NumBindPairs != 3 ||
- f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
- f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
- f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
+ if (f->NumPackStreams != 4
+ || f->PackStreams[0] != 2
+ || f->PackStreams[1] != 6
+ || f->PackStreams[2] != 1
+ || f->PackStreams[3] != 0
+ || f->NumBonds != 3
+ || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0
+ || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1
+ || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)
return SZ_ERROR_UNSUPPORTED;
return SZ_OK;
}
+
return SZ_ERROR_UNSUPPORTED;
}
-static UInt64 GetSum(const UInt64 *values, UInt32 index)
-{
- UInt64 sum = 0;
- UInt32 i;
- for (i = 0; i < index; i++)
- sum += values[i];
- return sum;
-}
-
#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
-static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
+static SRes SzFolder_Decode2(const CSzFolder *folder,
+ const Byte *propsData,
+ const UInt64 *unpackSizes,
+ const UInt64 *packPositions,
ILookInStream *inStream, UInt64 startPos,
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
Byte *tempBuf[])
@@ -346,7 +384,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
for (ci = 0; ci < folder->NumCoders; ci++)
{
- CSzCoderInfo *coder = &folder->Coders[ci];
+ const CSzCoderInfo *coder = &folder->Coders[ci];
if (IS_MAIN_METHOD((UInt32)coder->MethodID))
{
@@ -358,7 +396,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
if (folder->NumCoders == 4)
{
UInt32 indices[] = { 3, 2, 0 };
- UInt64 unpackSize = folder->UnpackSizes[ci];
+ UInt64 unpackSize = unpackSizes[ci];
si = indices[ci];
if (ci < 2)
{
@@ -367,7 +405,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
if (outSizeCur != unpackSize)
return SZ_ERROR_MEM;
temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
- if (temp == 0 && outSizeCur != 0)
+ if (!temp && outSizeCur != 0)
return SZ_ERROR_MEM;
outBufCur = tempBuf[1 - ci] = temp;
tempSizes[1 - ci] = outSizeCur;
@@ -382,8 +420,8 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
else
return SZ_ERROR_UNSUPPORTED;
}
- offset = GetSum(packSizes, si);
- inSize = packSizes[si];
+ offset = packPositions[si];
+ inSize = packPositions[si + 1] - offset;
RINOK(LookInStream_SeekTo(inStream, startPos + offset));
if (coder->MethodID == k_Copy)
@@ -394,77 +432,160 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
}
else if (coder->MethodID == k_LZMA)
{
- RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
+ RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
}
+ #ifndef _7Z_NO_METHOD_LZMA2
else if (coder->MethodID == k_LZMA2)
{
- RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
+ RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
}
- else
+ #endif
+ #ifdef _7ZIP_PPMD_SUPPPORT
+ else if (coder->MethodID == k_PPMD)
{
- #ifdef _7ZIP_PPMD_SUPPPORT
- RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
- #else
- return SZ_ERROR_UNSUPPORTED;
- #endif
+ RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
}
+ #endif
+ else
+ return SZ_ERROR_UNSUPPORTED;
}
else if (coder->MethodID == k_BCJ2)
{
- UInt64 offset = GetSum(packSizes, 1);
- UInt64 s3Size = packSizes[1];
- SRes res;
+ UInt64 offset = packPositions[1];
+ UInt64 s3Size = packPositions[2] - offset;
+
if (ci != 3)
return SZ_ERROR_UNSUPPORTED;
- RINOK(LookInStream_SeekTo(inStream, startPos + offset));
+
tempSizes[2] = (SizeT)s3Size;
if (tempSizes[2] != s3Size)
return SZ_ERROR_MEM;
tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
- if (tempBuf[2] == 0 && tempSizes[2] != 0)
+ if (!tempBuf[2] && tempSizes[2] != 0)
return SZ_ERROR_MEM;
- res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
- RINOK(res)
+
+ RINOK(LookInStream_SeekTo(inStream, startPos + offset));
+ RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]));
+
+ if ((tempSizes[0] & 3) != 0 ||
+ (tempSizes[1] & 3) != 0 ||
+ tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
+ return SZ_ERROR_DATA;
- res = Bcj2_Decode(
- tempBuf3, tempSize3,
- tempBuf[0], tempSizes[0],
- tempBuf[1], tempSizes[1],
- tempBuf[2], tempSizes[2],
- outBuffer, outSize);
- RINOK(res)
- }
- else
- {
- if (ci != 1)
- return SZ_ERROR_UNSUPPORTED;
- switch(coder->MethodID)
{
- case k_BCJ:
+ CBcj2Dec p;
+
+ p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3;
+ p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];
+ p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];
+ p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];
+
+ p.dest = outBuffer;
+ p.destLim = outBuffer + outSize;
+
+ Bcj2Dec_Init(&p);
+ RINOK(Bcj2Dec_Decode(&p));
+
{
- UInt32 state;
- x86_Convert_Init(state);
- x86_Convert(outBuffer, outSize, 0, &state, 0);
- break;
+ unsigned i;
+ for (i = 0; i < 4; i++)
+ if (p.bufs[i] != p.lims[i])
+ return SZ_ERROR_DATA;
+
+ if (!Bcj2Dec_IsFinished(&p))
+ return SZ_ERROR_DATA;
+
+ if (p.dest != p.destLim
+ || p.state != BCJ2_STREAM_MAIN)
+ return SZ_ERROR_DATA;
}
- CASE_BRA_CONV(ARM)
- default:
- return SZ_ERROR_UNSUPPORTED;
}
}
+ #ifndef _7Z_NO_METHODS_FILTERS
+ else if (ci == 1)
+ {
+ if (coder->MethodID == k_Delta)
+ {
+ if (coder->PropsSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ {
+ Byte state[DELTA_STATE_SIZE];
+ Delta_Init(state);
+ Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
+ }
+ }
+ else
+ {
+ if (coder->PropsSize != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ switch (coder->MethodID)
+ {
+ case k_BCJ:
+ {
+ UInt32 state;
+ x86_Convert_Init(state);
+ x86_Convert(outBuffer, outSize, 0, &state, 0);
+ break;
+ }
+ CASE_BRA_CONV(PPC)
+ CASE_BRA_CONV(IA64)
+ CASE_BRA_CONV(SPARC)
+ CASE_BRA_CONV(ARM)
+ CASE_BRA_CONV(ARMT)
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ }
+ }
+ #endif
+ else
+ return SZ_ERROR_UNSUPPORTED;
}
+
return SZ_OK;
}
-SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
+
+SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
ILookInStream *inStream, UInt64 startPos,
- Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
+ Byte *outBuffer, size_t outSize,
+ ISzAlloc *allocMain)
{
- Byte *tempBuf[3] = { 0, 0, 0};
- int i;
- SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos,
- outBuffer, (SizeT)outSize, allocMain, tempBuf);
- for (i = 0; i < 3; i++)
- IAlloc_Free(allocMain, tempBuf[i]);
- return res;
+ SRes res;
+ CSzFolder folder;
+ CSzData sd;
+
+ const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
+ sd.Data = data;
+ sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex];
+
+ res = SzGetNextFolderItem(&folder, &sd);
+
+ if (res != SZ_OK)
+ return res;
+
+ if (sd.Size != 0
+ || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]
+ || outSize != SzAr_GetFolderUnpackSize(p, folderIndex))
+ return SZ_ERROR_FAIL;
+ {
+ unsigned i;
+ Byte *tempBuf[3] = { 0, 0, 0};
+
+ res = SzFolder_Decode2(&folder, data,
+ &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]],
+ p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
+ inStream, startPos,
+ outBuffer, (SizeT)outSize, allocMain, tempBuf);
+
+ for (i = 0; i < 3; i++)
+ IAlloc_Free(allocMain, tempBuf[i]);
+
+ if (res == SZ_OK)
+ if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex))
+ if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex])
+ res = SZ_ERROR_CRC;
+
+ return res;
+ }
}
diff --git a/lzma/C/7zIn.c b/lzma/C/7zIn.c
deleted file mode 100644
index f1a44928e2..0000000000
--- a/lzma/C/7zIn.c
+++ /dev/null
@@ -1,1402 +0,0 @@
-/* 7zIn.c -- 7z Input functions
-2010-10-29 : Igor Pavlov : Public domain */
-
-#include
-
-#include "7z.h"
-#include "7zCrc.h"
-#include "CpuArch.h"
-
-Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
-
-#define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; }
-
-#define NUM_FOLDER_CODERS_MAX 32
-#define NUM_CODER_STREAMS_MAX 32
-
-void SzCoderInfo_Init(CSzCoderInfo *p)
-{
- Buf_Init(&p->Props);
-}
-
-void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc)
-{
- Buf_Free(&p->Props, alloc);
- SzCoderInfo_Init(p);
-}
-
-void SzFolder_Init(CSzFolder *p)
-{
- p->Coders = 0;
- p->BindPairs = 0;
- p->PackStreams = 0;
- p->UnpackSizes = 0;
- p->NumCoders = 0;
- p->NumBindPairs = 0;
- p->NumPackStreams = 0;
- p->UnpackCRCDefined = 0;
- p->UnpackCRC = 0;
- p->NumUnpackStreams = 0;
-}
-
-void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc)
-{
- UInt32 i;
- if (p->Coders)
- for (i = 0; i < p->NumCoders; i++)
- SzCoderInfo_Free(&p->Coders[i], alloc);
- IAlloc_Free(alloc, p->Coders);
- IAlloc_Free(alloc, p->BindPairs);
- IAlloc_Free(alloc, p->PackStreams);
- IAlloc_Free(alloc, p->UnpackSizes);
- SzFolder_Init(p);
-}
-
-UInt32 SzFolder_GetNumOutStreams(CSzFolder *p)
-{
- UInt32 result = 0;
- UInt32 i;
- for (i = 0; i < p->NumCoders; i++)
- result += p->Coders[i].NumOutStreams;
- return result;
-}
-
-int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex)
-{
- UInt32 i;
- for (i = 0; i < p->NumBindPairs; i++)
- if (p->BindPairs[i].InIndex == inStreamIndex)
- return i;
- return -1;
-}
-
-
-int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex)
-{
- UInt32 i;
- for (i = 0; i < p->NumBindPairs; i++)
- if (p->BindPairs[i].OutIndex == outStreamIndex)
- return i;
- return -1;
-}
-
-UInt64 SzFolder_GetUnpackSize(CSzFolder *p)
-{
- int i = (int)SzFolder_GetNumOutStreams(p);
- if (i == 0)
- return 0;
- for (i--; i >= 0; i--)
- if (SzFolder_FindBindPairForOutStream(p, i) < 0)
- return p->UnpackSizes[i];
- /* throw 1; */
- return 0;
-}
-
-void SzFile_Init(CSzFileItem *p)
-{
- p->HasStream = 1;
- p->IsDir = 0;
- p->IsAnti = 0;
- p->CrcDefined = 0;
- p->MTimeDefined = 0;
-}
-
-void SzAr_Init(CSzAr *p)
-{
- p->PackSizes = 0;
- p->PackCRCsDefined = 0;
- p->PackCRCs = 0;
- p->Folders = 0;
- p->Files = 0;
- p->NumPackStreams = 0;
- p->NumFolders = 0;
- p->NumFiles = 0;
-}
-
-void SzAr_Free(CSzAr *p, ISzAlloc *alloc)
-{
- UInt32 i;
- if (p->Folders)
- for (i = 0; i < p->NumFolders; i++)
- SzFolder_Free(&p->Folders[i], alloc);
-
- IAlloc_Free(alloc, p->PackSizes);
- IAlloc_Free(alloc, p->PackCRCsDefined);
- IAlloc_Free(alloc, p->PackCRCs);
- IAlloc_Free(alloc, p->Folders);
- IAlloc_Free(alloc, p->Files);
- SzAr_Init(p);
-}
-
-
-void SzArEx_Init(CSzArEx *p)
-{
- SzAr_Init(&p->db);
- p->FolderStartPackStreamIndex = 0;
- p->PackStreamStartPositions = 0;
- p->FolderStartFileIndex = 0;
- p->FileIndexToFolderIndexMap = 0;
- p->FileNameOffsets = 0;
- Buf_Init(&p->FileNames);
-}
-
-void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc)
-{
- IAlloc_Free(alloc, p->FolderStartPackStreamIndex);
- IAlloc_Free(alloc, p->PackStreamStartPositions);
- IAlloc_Free(alloc, p->FolderStartFileIndex);
- IAlloc_Free(alloc, p->FileIndexToFolderIndexMap);
-
- IAlloc_Free(alloc, p->FileNameOffsets);
- Buf_Free(&p->FileNames, alloc);
-
- SzAr_Free(&p->db, alloc);
- SzArEx_Init(p);
-}
-
-/*
-UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const
-{
- return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
-}
-
-UInt64 GetFilePackSize(int fileIndex) const
-{
- int folderIndex = FileIndexToFolderIndexMap[fileIndex];
- if (folderIndex >= 0)
- {
- const CSzFolder &folderInfo = Folders[folderIndex];
- if (FolderStartFileIndex[folderIndex] == fileIndex)
- return GetFolderFullPackSize(folderIndex);
- }
- return 0;
-}
-*/
-
-#define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \
- if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; }
-
-static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc)
-{
- UInt32 startPos = 0;
- UInt64 startPosSize = 0;
- UInt32 i;
- UInt32 folderIndex = 0;
- UInt32 indexInFolder = 0;
- MY_ALLOC(UInt32, p->FolderStartPackStreamIndex, p->db.NumFolders, alloc);
- for (i = 0; i < p->db.NumFolders; i++)
- {
- p->FolderStartPackStreamIndex[i] = startPos;
- startPos += p->db.Folders[i].NumPackStreams;
- }
-
- MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc);
-
- for (i = 0; i < p->db.NumPackStreams; i++)
- {
- p->PackStreamStartPositions[i] = startPosSize;
- startPosSize += p->db.PackSizes[i];
- }
-
- MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc);
- MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc);
-
- for (i = 0; i < p->db.NumFiles; i++)
- {
- CSzFileItem *file = p->db.Files + i;
- int emptyStream = !file->HasStream;
- if (emptyStream && indexInFolder == 0)
- {
- p->FileIndexToFolderIndexMap[i] = (UInt32)-1;
- continue;
- }
- if (indexInFolder == 0)
- {
- /*
- v3.13 incorrectly worked with empty folders
- v4.07: Loop for skipping empty folders
- */
- for (;;)
- {
- if (folderIndex >= p->db.NumFolders)
- return SZ_ERROR_ARCHIVE;
- p->FolderStartFileIndex[folderIndex] = i;
- if (p->db.Folders[folderIndex].NumUnpackStreams != 0)
- break;
- folderIndex++;
- }
- }
- p->FileIndexToFolderIndexMap[i] = folderIndex;
- if (emptyStream)
- continue;
- indexInFolder++;
- if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams)
- {
- folderIndex++;
- indexInFolder = 0;
- }
- }
- return SZ_OK;
-}
-
-
-UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder)
-{
- return p->dataPos +
- p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder];
-}
-
-int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize)
-{
- UInt32 packStreamIndex = p->FolderStartPackStreamIndex[folderIndex];
- CSzFolder *folder = p->db.Folders + folderIndex;
- UInt64 size = 0;
- UInt32 i;
- for (i = 0; i < folder->NumPackStreams; i++)
- {
- UInt64 t = size + p->db.PackSizes[packStreamIndex + i];
- if (t < size) /* check it */
- return SZ_ERROR_FAIL;
- size = t;
- }
- *resSize = size;
- return SZ_OK;
-}
-
-
-/*
-SRes SzReadTime(const CObjectVector &dataVector,
- CObjectVector &files, UInt64 type)
-{
- CBoolVector boolVector;
- RINOK(ReadBoolVector2(files.Size(), boolVector))
-
- CStreamSwitch streamSwitch;
- RINOK(streamSwitch.Set(this, &dataVector));
-
- for (int i = 0; i < files.Size(); i++)
- {
- CSzFileItem &file = files[i];
- CArchiveFileTime fileTime;
- bool defined = boolVector[i];
- if (defined)
- {
- UInt32 low, high;
- RINOK(SzReadUInt32(low));
- RINOK(SzReadUInt32(high));
- fileTime.dwLowDateTime = low;
- fileTime.dwHighDateTime = high;
- }
- switch(type)
- {
- case k7zIdCTime: file.IsCTimeDefined = defined; if (defined) file.CTime = fileTime; break;
- case k7zIdATime: file.IsATimeDefined = defined; if (defined) file.ATime = fileTime; break;
- case k7zIdMTime: file.IsMTimeDefined = defined; if (defined) file.MTime = fileTime; break;
- }
- }
- return SZ_OK;
-}
-*/
-
-static int TestSignatureCandidate(Byte *testBytes)
-{
- size_t i;
- for (i = 0; i < k7zSignatureSize; i++)
- if (testBytes[i] != k7zSignature[i])
- return 0;
- return 1;
-}
-
-typedef struct _CSzState
-{
- Byte *Data;
- size_t Size;
-}CSzData;
-
-static SRes SzReadByte(CSzData *sd, Byte *b)
-{
- if (sd->Size == 0)
- return SZ_ERROR_ARCHIVE;
- sd->Size--;
- *b = *sd->Data++;
- return SZ_OK;
-}
-
-static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size)
-{
- size_t i;
- for (i = 0; i < size; i++)
- {
- RINOK(SzReadByte(sd, data + i));
- }
- return SZ_OK;
-}
-
-static SRes SzReadUInt32(CSzData *sd, UInt32 *value)
-{
- int i;
- *value = 0;
- for (i = 0; i < 4; i++)
- {
- Byte b;
- RINOK(SzReadByte(sd, &b));
- *value |= ((UInt32)(b) << (8 * i));
- }
- return SZ_OK;
-}
-
-static SRes SzReadNumber(CSzData *sd, UInt64 *value)
-{
- Byte firstByte;
- Byte mask = 0x80;
- int i;
- RINOK(SzReadByte(sd, &firstByte));
- *value = 0;
- for (i = 0; i < 8; i++)
- {
- Byte b;
- if ((firstByte & mask) == 0)
- {
- UInt64 highPart = firstByte & (mask - 1);
- *value += (highPart << (8 * i));
- return SZ_OK;
- }
- RINOK(SzReadByte(sd, &b));
- *value |= ((UInt64)b << (8 * i));
- mask >>= 1;
- }
- return SZ_OK;
-}
-
-static SRes SzReadNumber32(CSzData *sd, UInt32 *value)
-{
- UInt64 value64;
- RINOK(SzReadNumber(sd, &value64));
- if (value64 >= 0x80000000)
- return SZ_ERROR_UNSUPPORTED;
- if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2)))
- return SZ_ERROR_UNSUPPORTED;
- *value = (UInt32)value64;
- return SZ_OK;
-}
-
-static SRes SzReadID(CSzData *sd, UInt64 *value)
-{
- return SzReadNumber(sd, value);
-}
-
-static SRes SzSkeepDataSize(CSzData *sd, UInt64 size)
-{
- if (size > sd->Size)
- return SZ_ERROR_ARCHIVE;
- sd->Size -= (size_t)size;
- sd->Data += (size_t)size;
- return SZ_OK;
-}
-
-static SRes SzSkeepData(CSzData *sd)
-{
- UInt64 size;
- RINOK(SzReadNumber(sd, &size));
- return SzSkeepDataSize(sd, size);
-}
-
-static SRes SzReadArchiveProperties(CSzData *sd)
-{
- for (;;)
- {
- UInt64 type;
- RINOK(SzReadID(sd, &type));
- if (type == k7zIdEnd)
- break;
- SzSkeepData(sd);
- }
- return SZ_OK;
-}
-
-static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute)
-{
- for (;;)
- {
- UInt64 type;
- RINOK(SzReadID(sd, &type));
- if (type == attribute)
- return SZ_OK;
- if (type == k7zIdEnd)
- return SZ_ERROR_ARCHIVE;
- RINOK(SzSkeepData(sd));
- }
-}
-
-static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc)
-{
- Byte b = 0;
- Byte mask = 0;
- size_t i;
- MY_ALLOC(Byte, *v, numItems, alloc);
- for (i = 0; i < numItems; i++)
- {
- if (mask == 0)
- {
- RINOK(SzReadByte(sd, &b));
- mask = 0x80;
- }
- (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0);
- mask >>= 1;
- }
- return SZ_OK;
-}
-
-static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc)
-{
- Byte allAreDefined;
- size_t i;
- RINOK(SzReadByte(sd, &allAreDefined));
- if (allAreDefined == 0)
- return SzReadBoolVector(sd, numItems, v, alloc);
- MY_ALLOC(Byte, *v, numItems, alloc);
- for (i = 0; i < numItems; i++)
- (*v)[i] = 1;
- return SZ_OK;
-}
-
-static SRes SzReadHashDigests(
- CSzData *sd,
- size_t numItems,
- Byte **digestsDefined,
- UInt32 **digests,
- ISzAlloc *alloc)
-{
- size_t i;
- RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, alloc));
- MY_ALLOC(UInt32, *digests, numItems, alloc);
- for (i = 0; i < numItems; i++)
- if ((*digestsDefined)[i])
- {
- RINOK(SzReadUInt32(sd, (*digests) + i));
- }
- return SZ_OK;
-}
-
-static SRes SzReadPackInfo(
- CSzData *sd,
- UInt64 *dataOffset,
- UInt32 *numPackStreams,
- UInt64 **packSizes,
- Byte **packCRCsDefined,
- UInt32 **packCRCs,
- ISzAlloc *alloc)
-{
- UInt32 i;
- RINOK(SzReadNumber(sd, dataOffset));
- RINOK(SzReadNumber32(sd, numPackStreams));
-
- RINOK(SzWaitAttribute(sd, k7zIdSize));
-
- MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc);
-
- for (i = 0; i < *numPackStreams; i++)
- {
- RINOK(SzReadNumber(sd, (*packSizes) + i));
- }
-
- for (;;)
- {
- UInt64 type;
- RINOK(SzReadID(sd, &type));
- if (type == k7zIdEnd)
- break;
- if (type == k7zIdCRC)
- {
- RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc));
- continue;
- }
- RINOK(SzSkeepData(sd));
- }
- if (*packCRCsDefined == 0)
- {
- MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, alloc);
- MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, alloc);
- for (i = 0; i < *numPackStreams; i++)
- {
- (*packCRCsDefined)[i] = 0;
- (*packCRCs)[i] = 0;
- }
- }
- return SZ_OK;
-}
-
-static SRes SzReadSwitch(CSzData *sd)
-{
- Byte external;
- RINOK(SzReadByte(sd, &external));
- return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
-}
-
-static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc)
-{
- UInt32 numCoders, numBindPairs, numPackStreams, i;
- UInt32 numInStreams = 0, numOutStreams = 0;
-
- RINOK(SzReadNumber32(sd, &numCoders));
- if (numCoders > NUM_FOLDER_CODERS_MAX)
- return SZ_ERROR_UNSUPPORTED;
- folder->NumCoders = numCoders;
-
- MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc);
-
- for (i = 0; i < numCoders; i++)
- SzCoderInfo_Init(folder->Coders + i);
-
- for (i = 0; i < numCoders; i++)
- {
- Byte mainByte;
- CSzCoderInfo *coder = folder->Coders + i;
- {
- unsigned idSize, j;
- Byte longID[15];
- RINOK(SzReadByte(sd, &mainByte));
- idSize = (unsigned)(mainByte & 0xF);
- RINOK(SzReadBytes(sd, longID, idSize));
- if (idSize > sizeof(coder->MethodID))
- return SZ_ERROR_UNSUPPORTED;
- coder->MethodID = 0;
- for (j = 0; j < idSize; j++)
- coder->MethodID |= (UInt64)longID[idSize - 1 - j] << (8 * j);
-
- if ((mainByte & 0x10) != 0)
- {
- RINOK(SzReadNumber32(sd, &coder->NumInStreams));
- RINOK(SzReadNumber32(sd, &coder->NumOutStreams));
- if (coder->NumInStreams > NUM_CODER_STREAMS_MAX ||
- coder->NumOutStreams > NUM_CODER_STREAMS_MAX)
- return SZ_ERROR_UNSUPPORTED;
- }
- else
- {
- coder->NumInStreams = 1;
- coder->NumOutStreams = 1;
- }
- if ((mainByte & 0x20) != 0)
- {
- UInt64 propertiesSize = 0;
- RINOK(SzReadNumber(sd, &propertiesSize));
- if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc))
- return SZ_ERROR_MEM;
- RINOK(SzReadBytes(sd, coder->Props.data, (size_t)propertiesSize));
- }
- }
- while ((mainByte & 0x80) != 0)
- {
- RINOK(SzReadByte(sd, &mainByte));
- RINOK(SzSkeepDataSize(sd, (mainByte & 0xF)));
- if ((mainByte & 0x10) != 0)
- {
- UInt32 n;
- RINOK(SzReadNumber32(sd, &n));
- RINOK(SzReadNumber32(sd, &n));
- }
- if ((mainByte & 0x20) != 0)
- {
- UInt64 propertiesSize = 0;
- RINOK(SzReadNumber(sd, &propertiesSize));
- RINOK(SzSkeepDataSize(sd, propertiesSize));
- }
- }
- numInStreams += coder->NumInStreams;
- numOutStreams += coder->NumOutStreams;
- }
-
- if (numOutStreams == 0)
- return SZ_ERROR_UNSUPPORTED;
-
- folder->NumBindPairs = numBindPairs = numOutStreams - 1;
- MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc);
-
- for (i = 0; i < numBindPairs; i++)
- {
- CSzBindPair *bp = folder->BindPairs + i;
- RINOK(SzReadNumber32(sd, &bp->InIndex));
- RINOK(SzReadNumber32(sd, &bp->OutIndex));
- }
-
- if (numInStreams < numBindPairs)
- return SZ_ERROR_UNSUPPORTED;
-
- folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs;
- MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc);
-
- if (numPackStreams == 1)
- {
- for (i = 0; i < numInStreams ; i++)
- if (SzFolder_FindBindPairForInStream(folder, i) < 0)
- break;
- if (i == numInStreams)
- return SZ_ERROR_UNSUPPORTED;
- folder->PackStreams[0] = i;
- }
- else
- for (i = 0; i < numPackStreams; i++)
- {
- RINOK(SzReadNumber32(sd, folder->PackStreams + i));
- }
- return SZ_OK;
-}
-
-static SRes SzReadUnpackInfo(
- CSzData *sd,
- UInt32 *numFolders,
- CSzFolder **folders, /* for alloc */
- ISzAlloc *alloc,
- ISzAlloc *allocTemp)
-{
- UInt32 i;
- RINOK(SzWaitAttribute(sd, k7zIdFolder));
- RINOK(SzReadNumber32(sd, numFolders));
- {
- RINOK(SzReadSwitch(sd));
-
- MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc);
-
- for (i = 0; i < *numFolders; i++)
- SzFolder_Init((*folders) + i);
-
- for (i = 0; i < *numFolders; i++)
- {
- RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc));
- }
- }
-
- RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize));
-
- for (i = 0; i < *numFolders; i++)
- {
- UInt32 j;
- CSzFolder *folder = (*folders) + i;
- UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder);
-
- MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc);
-
- for (j = 0; j < numOutStreams; j++)
- {
- RINOK(SzReadNumber(sd, folder->UnpackSizes + j));
- }
- }
-
- for (;;)
- {
- UInt64 type;
- RINOK(SzReadID(sd, &type));
- if (type == k7zIdEnd)
- return SZ_OK;
- if (type == k7zIdCRC)
- {
- SRes res;
- Byte *crcsDefined = 0;
- UInt32 *crcs = 0;
- res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp);
- if (res == SZ_OK)
- {
- for (i = 0; i < *numFolders; i++)
- {
- CSzFolder *folder = (*folders) + i;
- folder->UnpackCRCDefined = crcsDefined[i];
- folder->UnpackCRC = crcs[i];
- }
- }
- IAlloc_Free(allocTemp, crcs);
- IAlloc_Free(allocTemp, crcsDefined);
- RINOK(res);
- continue;
- }
- RINOK(SzSkeepData(sd));
- }
-}
-
-static SRes SzReadSubStreamsInfo(
- CSzData *sd,
- UInt32 numFolders,
- CSzFolder *folders,
- UInt32 *numUnpackStreams,
- UInt64 **unpackSizes,
- Byte **digestsDefined,
- UInt32 **digests,
- ISzAlloc *allocTemp)
-{
- UInt64 type = 0;
- UInt32 i;
- UInt32 si = 0;
- UInt32 numDigests = 0;
-
- for (i = 0; i < numFolders; i++)
- folders[i].NumUnpackStreams = 1;
- *numUnpackStreams = numFolders;
-
- for (;;)
- {
- RINOK(SzReadID(sd, &type));
- if (type == k7zIdNumUnpackStream)
- {
- *numUnpackStreams = 0;
- for (i = 0; i < numFolders; i++)
- {
- UInt32 numStreams;
- RINOK(SzReadNumber32(sd, &numStreams));
- folders[i].NumUnpackStreams = numStreams;
- *numUnpackStreams += numStreams;
- }
- continue;
- }
- if (type == k7zIdCRC || type == k7zIdSize)
- break;
- if (type == k7zIdEnd)
- break;
- RINOK(SzSkeepData(sd));
- }
-
- if (*numUnpackStreams == 0)
- {
- *unpackSizes = 0;
- *digestsDefined = 0;
- *digests = 0;
- }
- else
- {
- *unpackSizes = (UInt64 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt64));
- RINOM(*unpackSizes);
- *digestsDefined = (Byte *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(Byte));
- RINOM(*digestsDefined);
- *digests = (UInt32 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt32));
- RINOM(*digests);
- }
-
- for (i = 0; i < numFolders; i++)
- {
- /*
- v3.13 incorrectly worked with empty folders
- v4.07: we check that folder is empty
- */
- UInt64 sum = 0;
- UInt32 j;
- UInt32 numSubstreams = folders[i].NumUnpackStreams;
- if (numSubstreams == 0)
- continue;
- if (type == k7zIdSize)
- for (j = 1; j < numSubstreams; j++)
- {
- UInt64 size;
- RINOK(SzReadNumber(sd, &size));
- (*unpackSizes)[si++] = size;
- sum += size;
- }
- (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum;
- }
- if (type == k7zIdSize)
- {
- RINOK(SzReadID(sd, &type));
- }
-
- for (i = 0; i < *numUnpackStreams; i++)
- {
- (*digestsDefined)[i] = 0;
- (*digests)[i] = 0;
- }
-
-
- for (i = 0; i < numFolders; i++)
- {
- UInt32 numSubstreams = folders[i].NumUnpackStreams;
- if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
- numDigests += numSubstreams;
- }
-
-
- si = 0;
- for (;;)
- {
- if (type == k7zIdCRC)
- {
- int digestIndex = 0;
- Byte *digestsDefined2 = 0;
- UInt32 *digests2 = 0;
- SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp);
- if (res == SZ_OK)
- {
- for (i = 0; i < numFolders; i++)
- {
- CSzFolder *folder = folders + i;
- UInt32 numSubstreams = folder->NumUnpackStreams;
- if (numSubstreams == 1 && folder->UnpackCRCDefined)
- {
- (*digestsDefined)[si] = 1;
- (*digests)[si] = folder->UnpackCRC;
- si++;
- }
- else
- {
- UInt32 j;
- for (j = 0; j < numSubstreams; j++, digestIndex++)
- {
- (*digestsDefined)[si] = digestsDefined2[digestIndex];
- (*digests)[si] = digests2[digestIndex];
- si++;
- }
- }
- }
- }
- IAlloc_Free(allocTemp, digestsDefined2);
- IAlloc_Free(allocTemp, digests2);
- RINOK(res);
- }
- else if (type == k7zIdEnd)
- return SZ_OK;
- else
- {
- RINOK(SzSkeepData(sd));
- }
- RINOK(SzReadID(sd, &type));
- }
-}
-
-
-static SRes SzReadStreamsInfo(
- CSzData *sd,
- UInt64 *dataOffset,
- CSzAr *p,
- UInt32 *numUnpackStreams,
- UInt64 **unpackSizes, /* allocTemp */
- Byte **digestsDefined, /* allocTemp */
- UInt32 **digests, /* allocTemp */
- ISzAlloc *alloc,
- ISzAlloc *allocTemp)
-{
- for (;;)
- {
- UInt64 type;
- RINOK(SzReadID(sd, &type));
- if ((UInt64)(int)type != type)
- return SZ_ERROR_UNSUPPORTED;
- switch((int)type)
- {
- case k7zIdEnd:
- return SZ_OK;
- case k7zIdPackInfo:
- {
- RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams,
- &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc));
- break;
- }
- case k7zIdUnpackInfo:
- {
- RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp));
- break;
- }
- case k7zIdSubStreamsInfo:
- {
- RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders,
- numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp));
- break;
- }
- default:
- return SZ_ERROR_UNSUPPORTED;
- }
- }
-}
-
-size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
-{
- size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
- if (dest != 0)
- {
- size_t i;
- const Byte *src = p->FileNames.data + (p->FileNameOffsets[fileIndex] * 2);
- for (i = 0; i < len; i++)
- dest[i] = GetUi16(src + i * 2);
- }
- return len;
-}
-
-static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes)
-{
- UInt32 i;
- size_t pos = 0;
- for (i = 0; i < numFiles; i++)
- {
- sizes[i] = pos;
- for (;;)
- {
- if (pos >= size)
- return SZ_ERROR_ARCHIVE;
- if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0)
- break;
- pos++;
- }
- pos++;
- }
- sizes[i] = pos;
- return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
-}
-
-static SRes SzReadHeader2(
- CSzArEx *p, /* allocMain */
- CSzData *sd,
- UInt64 **unpackSizes, /* allocTemp */
- Byte **digestsDefined, /* allocTemp */
- UInt32 **digests, /* allocTemp */
- Byte **emptyStreamVector, /* allocTemp */
- Byte **emptyFileVector, /* allocTemp */
- Byte **lwtVector, /* allocTemp */
- ISzAlloc *allocMain,
- ISzAlloc *allocTemp)
-{
- UInt64 type;
- UInt32 numUnpackStreams = 0;
- UInt32 numFiles = 0;
- CSzFileItem *files = 0;
- UInt32 numEmptyStreams = 0;
- UInt32 i;
-
- RINOK(SzReadID(sd, &type));
-
- if (type == k7zIdArchiveProperties)
- {
- RINOK(SzReadArchiveProperties(sd));
- RINOK(SzReadID(sd, &type));
- }
-
-
- if (type == k7zIdMainStreamsInfo)
- {
- RINOK(SzReadStreamsInfo(sd,
- &p->dataPos,
- &p->db,
- &numUnpackStreams,
- unpackSizes,
- digestsDefined,
- digests, allocMain, allocTemp));
- p->dataPos += p->startPosAfterHeader;
- RINOK(SzReadID(sd, &type));
- }
-
- if (type == k7zIdEnd)
- return SZ_OK;
- if (type != k7zIdFilesInfo)
- return SZ_ERROR_ARCHIVE;
-
- RINOK(SzReadNumber32(sd, &numFiles));
- p->db.NumFiles = numFiles;
-
- MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain);
-
- p->db.Files = files;
- for (i = 0; i < numFiles; i++)
- SzFile_Init(files + i);
-
- for (;;)
- {
- UInt64 type;
- UInt64 size;
- RINOK(SzReadID(sd, &type));
- if (type == k7zIdEnd)
- break;
- RINOK(SzReadNumber(sd, &size));
- if (size > sd->Size)
- return SZ_ERROR_ARCHIVE;
- if ((UInt64)(int)type != type)
- {
- RINOK(SzSkeepDataSize(sd, size));
- }
- else
- switch((int)type)
- {
- case k7zIdName:
- {
- size_t namesSize;
- RINOK(SzReadSwitch(sd));
- namesSize = (size_t)size - 1;
- if ((namesSize & 1) != 0)
- return SZ_ERROR_ARCHIVE;
- if (!Buf_Create(&p->FileNames, namesSize, allocMain))
- return SZ_ERROR_MEM;
- MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain);
- memcpy(p->FileNames.data, sd->Data, namesSize);
- RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets))
- RINOK(SzSkeepDataSize(sd, namesSize));
- break;
- }
- case k7zIdEmptyStream:
- {
- RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp));
- numEmptyStreams = 0;
- for (i = 0; i < numFiles; i++)
- if ((*emptyStreamVector)[i])
- numEmptyStreams++;
- break;
- }
- case k7zIdEmptyFile:
- {
- RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp));
- break;
- }
- case k7zIdWinAttributes:
- {
- RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp));
- RINOK(SzReadSwitch(sd));
- for (i = 0; i < numFiles; i++)
- {
- CSzFileItem *f = &files[i];
- Byte defined = (*lwtVector)[i];
- f->AttribDefined = defined;
- f->Attrib = 0;
- if (defined)
- {
- RINOK(SzReadUInt32(sd, &f->Attrib));
- }
- }
- IAlloc_Free(allocTemp, *lwtVector);
- *lwtVector = NULL;
- break;
- }
- case k7zIdMTime:
- {
- RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp));
- RINOK(SzReadSwitch(sd));
- for (i = 0; i < numFiles; i++)
- {
- CSzFileItem *f = &files[i];
- Byte defined = (*lwtVector)[i];
- f->MTimeDefined = defined;
- f->MTime.Low = f->MTime.High = 0;
- if (defined)
- {
- RINOK(SzReadUInt32(sd, &f->MTime.Low));
- RINOK(SzReadUInt32(sd, &f->MTime.High));
- }
- }
- IAlloc_Free(allocTemp, *lwtVector);
- *lwtVector = NULL;
- break;
- }
- default:
- {
- RINOK(SzSkeepDataSize(sd, size));
- }
- }
- }
-
- {
- UInt32 emptyFileIndex = 0;
- UInt32 sizeIndex = 0;
- for (i = 0; i < numFiles; i++)
- {
- CSzFileItem *file = files + i;
- file->IsAnti = 0;
- if (*emptyStreamVector == 0)
- file->HasStream = 1;
- else
- file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1);
- if (file->HasStream)
- {
- file->IsDir = 0;
- file->Size = (*unpackSizes)[sizeIndex];
- file->Crc = (*digests)[sizeIndex];
- file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex];
- sizeIndex++;
- }
- else
- {
- if (*emptyFileVector == 0)
- file->IsDir = 1;
- else
- file->IsDir = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1);
- emptyFileIndex++;
- file->Size = 0;
- file->Crc = 0;
- file->CrcDefined = 0;
- }
- }
- }
- return SzArEx_Fill(p, allocMain);
-}
-
-static SRes SzReadHeader(
- CSzArEx *p,
- CSzData *sd,
- ISzAlloc *allocMain,
- ISzAlloc *allocTemp)
-{
- UInt64 *unpackSizes = 0;
- Byte *digestsDefined = 0;
- UInt32 *digests = 0;
- Byte *emptyStreamVector = 0;
- Byte *emptyFileVector = 0;
- Byte *lwtVector = 0;
- SRes res = SzReadHeader2(p, sd,
- &unpackSizes, &digestsDefined, &digests,
- &emptyStreamVector, &emptyFileVector, &lwtVector,
- allocMain, allocTemp);
- IAlloc_Free(allocTemp, unpackSizes);
- IAlloc_Free(allocTemp, digestsDefined);
- IAlloc_Free(allocTemp, digests);
- IAlloc_Free(allocTemp, emptyStreamVector);
- IAlloc_Free(allocTemp, emptyFileVector);
- IAlloc_Free(allocTemp, lwtVector);
- return res;
-}
-
-static SRes SzReadAndDecodePackedStreams2(
- ILookInStream *inStream,
- CSzData *sd,
- CBuf *outBuffer,
- UInt64 baseOffset,
- CSzAr *p,
- UInt64 **unpackSizes,
- Byte **digestsDefined,
- UInt32 **digests,
- ISzAlloc *allocTemp)
-{
-
- UInt32 numUnpackStreams = 0;
- UInt64 dataStartPos;
- CSzFolder *folder;
- UInt64 unpackSize;
- SRes res;
-
- RINOK(SzReadStreamsInfo(sd, &dataStartPos, p,
- &numUnpackStreams, unpackSizes, digestsDefined, digests,
- allocTemp, allocTemp));
-
- dataStartPos += baseOffset;
- if (p->NumFolders != 1)
- return SZ_ERROR_ARCHIVE;
-
- folder = p->Folders;
- unpackSize = SzFolder_GetUnpackSize(folder);
-
- RINOK(LookInStream_SeekTo(inStream, dataStartPos));
-
- if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp))
- return SZ_ERROR_MEM;
-
- res = SzFolder_Decode(folder, p->PackSizes,
- inStream, dataStartPos,
- outBuffer->data, (size_t)unpackSize, allocTemp);
- RINOK(res);
- if (folder->UnpackCRCDefined)
- if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC)
- return SZ_ERROR_CRC;
- return SZ_OK;
-}
-
-static SRes SzReadAndDecodePackedStreams(
- ILookInStream *inStream,
- CSzData *sd,
- CBuf *outBuffer,
- UInt64 baseOffset,
- ISzAlloc *allocTemp)
-{
- CSzAr p;
- UInt64 *unpackSizes = 0;
- Byte *digestsDefined = 0;
- UInt32 *digests = 0;
- SRes res;
- SzAr_Init(&p);
- res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset,
- &p, &unpackSizes, &digestsDefined, &digests,
- allocTemp);
- SzAr_Free(&p, allocTemp);
- IAlloc_Free(allocTemp, unpackSizes);
- IAlloc_Free(allocTemp, digestsDefined);
- IAlloc_Free(allocTemp, digests);
- return res;
-}
-
-static SRes SzArEx_Open2(
- CSzArEx *p,
- ILookInStream *inStream,
- ISzAlloc *allocMain,
- ISzAlloc *allocTemp)
-{
- Byte header[k7zStartHeaderSize];
- Int64 startArcPos;
- UInt64 nextHeaderOffset, nextHeaderSize;
- size_t nextHeaderSizeT;
- UInt32 nextHeaderCRC;
- CBuf buffer;
- SRes res;
-
- startArcPos = 0;
- RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR));
-
- RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));
-
- if (!TestSignatureCandidate(header))
- return SZ_ERROR_NO_ARCHIVE;
- if (header[6] != k7zMajorVersion)
- return SZ_ERROR_UNSUPPORTED;
-
- nextHeaderOffset = GetUi64(header + 12);
- nextHeaderSize = GetUi64(header + 20);
- nextHeaderCRC = GetUi32(header + 28);
-
- p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;
-
- if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
- return SZ_ERROR_CRC;
-
- nextHeaderSizeT = (size_t)nextHeaderSize;
- if (nextHeaderSizeT != nextHeaderSize)
- return SZ_ERROR_MEM;
- if (nextHeaderSizeT == 0)
- return SZ_OK;
- if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize ||
- nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize)
- return SZ_ERROR_NO_ARCHIVE;
-
- {
- Int64 pos = 0;
- RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END));
- if ((UInt64)pos < startArcPos + nextHeaderOffset ||
- (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
- (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
- return SZ_ERROR_INPUT_EOF;
- }
-
- RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));
-
- if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp))
- return SZ_ERROR_MEM;
-
- res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT);
- if (res == SZ_OK)
- {
- res = SZ_ERROR_ARCHIVE;
- if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC)
- {
- CSzData sd;
- UInt64 type;
- sd.Data = buffer.data;
- sd.Size = buffer.size;
- res = SzReadID(&sd, &type);
- if (res == SZ_OK)
- {
- if (type == k7zIdEncodedHeader)
- {
- CBuf outBuffer;
- Buf_Init(&outBuffer);
- res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp);
- if (res != SZ_OK)
- Buf_Free(&outBuffer, allocTemp);
- else
- {
- Buf_Free(&buffer, allocTemp);
- buffer.data = outBuffer.data;
- buffer.size = outBuffer.size;
- sd.Data = buffer.data;
- sd.Size = buffer.size;
- res = SzReadID(&sd, &type);
- }
- }
- }
- if (res == SZ_OK)
- {
- if (type == k7zIdHeader)
- res = SzReadHeader(p, &sd, allocMain, allocTemp);
- else
- res = SZ_ERROR_UNSUPPORTED;
- }
- }
- }
- Buf_Free(&buffer, allocTemp);
- return res;
-}
-
-SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp)
-{
- SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
- if (res != SZ_OK)
- SzArEx_Free(p, allocMain);
- return res;
-}
-
-SRes SzArEx_Extract(
- const CSzArEx *p,
- ILookInStream *inStream,
- UInt32 fileIndex,
- UInt32 *blockIndex,
- Byte **outBuffer,
- size_t *outBufferSize,
- size_t *offset,
- size_t *outSizeProcessed,
- ISzAlloc *allocMain,
- ISzAlloc *allocTemp)
-{
- UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex];
- SRes res = SZ_OK;
- *offset = 0;
- *outSizeProcessed = 0;
- if (folderIndex == (UInt32)-1)
- {
- IAlloc_Free(allocMain, *outBuffer);
- *blockIndex = folderIndex;
- *outBuffer = 0;
- *outBufferSize = 0;
- return SZ_OK;
- }
-
- if (*outBuffer == 0 || *blockIndex != folderIndex)
- {
- CSzFolder *folder = p->db.Folders + folderIndex;
- UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder);
- size_t unpackSize = (size_t)unpackSizeSpec;
- UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0);
-
- if (unpackSize != unpackSizeSpec)
- return SZ_ERROR_MEM;
- *blockIndex = folderIndex;
- IAlloc_Free(allocMain, *outBuffer);
- *outBuffer = 0;
-
- RINOK(LookInStream_SeekTo(inStream, startOffset));
-
- if (res == SZ_OK)
- {
- *outBufferSize = unpackSize;
- if (unpackSize != 0)
- {
- *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize);
- if (*outBuffer == 0)
- res = SZ_ERROR_MEM;
- }
- if (res == SZ_OK)
- {
- res = SzFolder_Decode(folder,
- p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex],
- inStream, startOffset,
- *outBuffer, unpackSize, allocTemp);
- if (res == SZ_OK)
- {
- if (folder->UnpackCRCDefined)
- {
- if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC)
- res = SZ_ERROR_CRC;
- }
- }
- }
- }
- }
- if (res == SZ_OK)
- {
- UInt32 i;
- CSzFileItem *fileItem = p->db.Files + fileIndex;
- *offset = 0;
- for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++)
- *offset += (UInt32)p->db.Files[i].Size;
- *outSizeProcessed = (size_t)fileItem->Size;
- if (*offset + *outSizeProcessed > *outBufferSize)
- return SZ_ERROR_FAIL;
- if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc)
- res = SZ_ERROR_CRC;
- }
- return res;
-}
diff --git a/lzma/C/7zStream.c b/lzma/C/7zStream.c
index f0959fb078..5a92d532cc 100644
--- a/lzma/C/7zStream.c
+++ b/lzma/C/7zStream.c
@@ -1,9 +1,11 @@
/* 7zStream.c -- 7z Stream functions
-2010-03-11 : Igor Pavlov : Public domain */
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include
-#include "Types.h"
+#include "7zTypes.h"
SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType)
{
diff --git a/lzma/C/Types.h b/lzma/C/7zTypes.h
similarity index 93%
rename from lzma/C/Types.h
rename to lzma/C/7zTypes.h
index f193ce2f53..f39d103262 100644
--- a/lzma/C/Types.h
+++ b/lzma/C/7zTypes.h
@@ -1,15 +1,15 @@
-/* Types.h -- Basic types
-2010-10-09 : Igor Pavlov : Public domain */
+/* 7zTypes.h -- Basic types
+2013-11-12 : Igor Pavlov : Public domain */
#ifndef __7Z_TYPES_H
#define __7Z_TYPES_H
-#include
-
#ifdef _WIN32
#include
#endif
+#include
+
#ifndef EXTERN_C_BEGIN
#ifdef __cplusplus
#define EXTERN_C_BEGIN extern "C" {
@@ -44,6 +44,7 @@ typedef int SRes;
#ifdef _WIN32
typedef DWORD WRes;
+/* typedef unsigned WRes; */
#else
typedef int WRes;
#endif
@@ -116,6 +117,7 @@ typedef int Bool;
#else
+#define MY_NO_INLINE
#define MY_CDECL
#define MY_FAST_CALL
diff --git a/lzma/C/7zVersion.h b/lzma/C/7zVersion.h
index 43f0fef6ff..52ad3c1b16 100644
--- a/lzma/C/7zVersion.h
+++ b/lzma/C/7zVersion.h
@@ -1,8 +1,19 @@
-#define MY_VER_MAJOR 9
-#define MY_VER_MINOR 22
-#define MY_VER_BUILD 00
-#define MY_VERSION "9.22 beta"
-#define MY_7ZIP_VERSION "9.22 beta"
-#define MY_DATE "2011-04-18"
-#define MY_COPYRIGHT ": Igor Pavlov : Public domain"
-#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE
+#define MY_VER_MAJOR 15
+#define MY_VER_MINOR 14
+#define MY_VER_BUILD 0
+#define MY_VERSION_NUMBERS "15.14"
+#define MY_VERSION "15.14"
+#define MY_DATE "2015-12-31"
+#undef MY_COPYRIGHT
+#undef MY_VERSION_COPYRIGHT_DATE
+#define MY_AUTHOR_NAME "Igor Pavlov"
+#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
+#define MY_COPYRIGHT_CR "Copyright (c) 1999-2015 Igor Pavlov"
+
+#ifdef USE_COPYRIGHT_CR
+ #define MY_COPYRIGHT MY_COPYRIGHT_CR
+#else
+ #define MY_COPYRIGHT MY_COPYRIGHT_PD
+#endif
+
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " : " MY_COPYRIGHT " : " MY_DATE
diff --git a/lzma/C/Bcj2.c b/lzma/C/Bcj2.c
index 474bdd45d3..707362a615 100644
--- a/lzma/C/Bcj2.c
+++ b/lzma/C/Bcj2.c
@@ -1,132 +1,256 @@
-/* Bcj2.c -- Converter for x86 code (BCJ2)
-2008-10-04 : Igor Pavlov : Public domain */
+/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code)
+2015-08-01 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include "Bcj2.h"
+#include "CpuArch.h"
-#ifdef _LZMA_PROB32
-#define CProb UInt32
-#else
#define CProb UInt16
-#endif
-#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)
-#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))
-
-#define kNumTopBits 24
-#define kTopValue ((UInt32)1 << kNumTopBits)
-
-#define kNumBitModelTotalBits 11
-#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kTopValue ((UInt32)1 << 24)
+#define kNumModelBits 11
+#define kBitModelTotal (1 << kNumModelBits)
#define kNumMoveBits 5
-#define RC_READ_BYTE (*buffer++)
-#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
-#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \
- { int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }}
+#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound)
+#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits));
-#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; }
-
-#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
-#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE;
-#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE;
-
-int Bcj2_Decode(
- const Byte *buf0, SizeT size0,
- const Byte *buf1, SizeT size1,
- const Byte *buf2, SizeT size2,
- const Byte *buf3, SizeT size3,
- Byte *outBuf, SizeT outSize)
+void Bcj2Dec_Init(CBcj2Dec *p)
{
- CProb p[256 + 2];
- SizeT inPos = 0, outPos = 0;
+ unsigned i;
- const Byte *buffer, *bufferLim;
- UInt32 range, code;
- Byte prevByte = 0;
+ p->state = BCJ2_DEC_STATE_OK;
+ p->ip = 0;
+ p->temp[3] = 0;
+ p->range = 0;
+ p->code = 0;
+ for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
+ p->probs[i] = kBitModelTotal >> 1;
+}
- unsigned int i;
- for (i = 0; i < sizeof(p) / sizeof(p[0]); i++)
- p[i] = kBitModelTotal >> 1;
+SRes Bcj2Dec_Decode(CBcj2Dec *p)
+{
+ if (p->range <= 5)
+ {
+ p->state = BCJ2_DEC_STATE_OK;
+ for (; p->range != 5; p->range++)
+ {
+ if (p->range == 1 && p->code != 0)
+ return SZ_ERROR_DATA;
+
+ if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
+ {
+ p->state = BCJ2_STREAM_RC;
+ return SZ_OK;
+ }
- buffer = buf3;
- bufferLim = buffer + size3;
- RC_INIT2
+ p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
+ }
+
+ if (p->code == 0xFFFFFFFF)
+ return SZ_ERROR_DATA;
+
+ p->range = 0xFFFFFFFF;
+ }
+ else if (p->state >= BCJ2_DEC_STATE_ORIG_0)
+ {
+ while (p->state <= BCJ2_DEC_STATE_ORIG_3)
+ {
+ Byte *dest = p->dest;
+ if (dest == p->destLim)
+ return SZ_OK;
+ *dest = p->temp[p->state++ - BCJ2_DEC_STATE_ORIG_0];
+ p->dest = dest + 1;
+ }
+ }
- if (outSize == 0)
- return SZ_OK;
+ /*
+ if (BCJ2_IS_32BIT_STREAM(p->state))
+ {
+ const Byte *cur = p->bufs[p->state];
+ if (cur == p->lims[p->state])
+ return SZ_OK;
+ p->bufs[p->state] = cur + 4;
+
+ {
+ UInt32 val;
+ Byte *dest;
+ SizeT rem;
+
+ p->ip += 4;
+ val = GetBe32(cur) - p->ip;
+ dest = p->dest;
+ rem = p->destLim - dest;
+ if (rem < 4)
+ {
+ SizeT i;
+ SetUi32(p->temp, val);
+ for (i = 0; i < rem; i++)
+ dest[i] = p->temp[i];
+ p->dest = dest + rem;
+ p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;
+ return SZ_OK;
+ }
+ SetUi32(dest, val);
+ p->temp[3] = (Byte)(val >> 24);
+ p->dest = dest + 4;
+ p->state = BCJ2_DEC_STATE_OK;
+ }
+ }
+ */
for (;;)
{
- Byte b;
- CProb *prob;
- UInt32 bound;
- UInt32 ttt;
-
- SizeT limit = size0 - inPos;
- if (outSize - outPos < limit)
- limit = outSize - outPos;
- while (limit != 0)
- {
- Byte b = buf0[inPos];
- outBuf[outPos++] = b;
- if (IsJ(prevByte, b))
- break;
- inPos++;
- prevByte = b;
- limit--;
- }
-
- if (limit == 0 || outPos == outSize)
- break;
-
- b = buf0[inPos++];
-
- if (b == 0xE8)
- prob = p + prevByte;
- else if (b == 0xE9)
- prob = p + 256;
- else
- prob = p + 257;
-
- IF_BIT_0(prob)
- {
- UPDATE_0(prob)
- prevByte = b;
- }
+ if (BCJ2_IS_32BIT_STREAM(p->state))
+ p->state = BCJ2_DEC_STATE_OK;
else
{
- UInt32 dest;
- const Byte *v;
- UPDATE_1(prob)
- if (b == 0xE8)
+ if (p->range < kTopValue)
{
- v = buf1;
- if (size1 < 4)
- return SZ_ERROR_DATA;
- buf1 += 4;
- size1 -= 4;
+ if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
+ {
+ p->state = BCJ2_STREAM_RC;
+ return SZ_OK;
+ }
+ p->range <<= 8;
+ p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
}
- else
+
{
- v = buf2;
- if (size2 < 4)
- return SZ_ERROR_DATA;
- buf2 += 4;
- size2 -= 4;
+ const Byte *src = p->bufs[BCJ2_STREAM_MAIN];
+ const Byte *srcLim;
+ Byte *dest;
+ SizeT num = p->lims[BCJ2_STREAM_MAIN] - src;
+
+ if (num == 0)
+ {
+ p->state = BCJ2_STREAM_MAIN;
+ return SZ_OK;
+ }
+
+ dest = p->dest;
+ if (num > (SizeT)(p->destLim - dest))
+ {
+ num = p->destLim - dest;
+ if (num == 0)
+ {
+ p->state = BCJ2_DEC_STATE_ORIG;
+ return SZ_OK;
+ }
+ }
+
+ srcLim = src + num;
+
+ if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80)
+ *dest = src[0];
+ else for (;;)
+ {
+ Byte b = *src;
+ *dest = b;
+ if (b != 0x0F)
+ {
+ if ((b & 0xFE) == 0xE8)
+ break;
+ dest++;
+ if (++src != srcLim)
+ continue;
+ break;
+ }
+ dest++;
+ if (++src == srcLim)
+ break;
+ if ((*src & 0xF0) != 0x80)
+ continue;
+ *dest = *src;
+ break;
+ }
+
+ num = src - p->bufs[BCJ2_STREAM_MAIN];
+
+ if (src == srcLim)
+ {
+ p->temp[3] = src[-1];
+ p->bufs[BCJ2_STREAM_MAIN] = src;
+ p->ip += (UInt32)num;
+ p->dest += num;
+ p->state =
+ p->bufs[BCJ2_STREAM_MAIN] ==
+ p->lims[BCJ2_STREAM_MAIN] ?
+ (unsigned)BCJ2_STREAM_MAIN :
+ (unsigned)BCJ2_DEC_STATE_ORIG;
+ return SZ_OK;
+ }
+
+ {
+ UInt32 bound, ttt;
+ CProb *prob;
+ Byte b = src[0];
+ Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]);
+
+ p->temp[3] = b;
+ p->bufs[BCJ2_STREAM_MAIN] = src + 1;
+ num++;
+ p->ip += (UInt32)num;
+ p->dest += num;
+
+ prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0));
+
+ _IF_BIT_0
+ {
+ _UPDATE_0
+ continue;
+ }
+ _UPDATE_1
+
+ }
}
- dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) |
- ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4);
- outBuf[outPos++] = (Byte)dest;
- if (outPos == outSize)
+ }
+
+ {
+ UInt32 val;
+ unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;
+ const Byte *cur = p->bufs[cj];
+ Byte *dest;
+ SizeT rem;
+
+ if (cur == p->lims[cj])
+ {
+ p->state = cj;
break;
- outBuf[outPos++] = (Byte)(dest >> 8);
- if (outPos == outSize)
+ }
+
+ val = GetBe32(cur);
+ p->bufs[cj] = cur + 4;
+
+ p->ip += 4;
+ val -= p->ip;
+ dest = p->dest;
+ rem = p->destLim - dest;
+
+ if (rem < 4)
+ {
+ SizeT i;
+ SetUi32(p->temp, val);
+ for (i = 0; i < rem; i++)
+ dest[i] = p->temp[i];
+ p->dest = dest + rem;
+ p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;
break;
- outBuf[outPos++] = (Byte)(dest >> 16);
- if (outPos == outSize)
- break;
- outBuf[outPos++] = prevByte = (Byte)(dest >> 24);
+ }
+
+ SetUi32(dest, val);
+ p->temp[3] = (Byte)(val >> 24);
+ p->dest = dest + 4;
}
}
- return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA;
+
+ if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC])
+ {
+ p->range <<= 8;
+ p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
+ }
+
+ return SZ_OK;
}
diff --git a/lzma/C/Bcj2.h b/lzma/C/Bcj2.h
index d9d857bc30..68893d2d12 100644
--- a/lzma/C/Bcj2.h
+++ b/lzma/C/Bcj2.h
@@ -1,38 +1,146 @@
-/* Bcj2.h -- Converter for x86 code (BCJ2)
-2009-02-07 : Igor Pavlov : Public domain */
+/* Bcj2.h -- BCJ2 Converter for x86 code
+2014-11-10 : Igor Pavlov : Public domain */
#ifndef __BCJ2_H
#define __BCJ2_H
-#include "Types.h"
+#include "7zTypes.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
+EXTERN_C_BEGIN
+
+#define BCJ2_NUM_STREAMS 4
+
+enum
+{
+ BCJ2_STREAM_MAIN,
+ BCJ2_STREAM_CALL,
+ BCJ2_STREAM_JUMP,
+ BCJ2_STREAM_RC
+};
+
+enum
+{
+ BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS,
+ BCJ2_DEC_STATE_ORIG_1,
+ BCJ2_DEC_STATE_ORIG_2,
+ BCJ2_DEC_STATE_ORIG_3,
+
+ BCJ2_DEC_STATE_ORIG,
+ BCJ2_DEC_STATE_OK
+};
+
+enum
+{
+ BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS,
+ BCJ2_ENC_STATE_OK
+};
+
+
+#define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP)
/*
-Conditions:
- outSize <= FullOutputSize,
- where FullOutputSize is full size of output stream of x86_2 filter.
-
-If buf0 overlaps outBuf, there are two required conditions:
- 1) (buf0 >= outBuf)
- 2) (buf0 + size0 >= outBuf + FullOutputSize).
-
-Returns:
- SZ_OK
- SZ_ERROR_DATA - Data error
+CBcj2Dec / CBcj2Enc
+bufs sizes:
+ BUF_SIZE(n) = lims[n] - bufs[n]
+bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4:
+ (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0
+ (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0
*/
-int Bcj2_Decode(
- const Byte *buf0, SizeT size0,
- const Byte *buf1, SizeT size1,
- const Byte *buf2, SizeT size2,
- const Byte *buf3, SizeT size3,
- Byte *outBuf, SizeT outSize);
+/*
+CBcj2Dec:
+dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions:
+ bufs[BCJ2_STREAM_MAIN] >= dest &&
+ bufs[BCJ2_STREAM_MAIN] - dest >= tempReserv +
+ BUF_SIZE(BCJ2_STREAM_CALL) +
+ BUF_SIZE(BCJ2_STREAM_JUMP)
+ tempReserv = 0 : for first call of Bcj2Dec_Decode
+ tempReserv = 4 : for any other calls of Bcj2Dec_Decode
+ overlap with offset = 1 is not allowed
+*/
-#ifdef __cplusplus
-}
-#endif
+typedef struct
+{
+ const Byte *bufs[BCJ2_NUM_STREAMS];
+ const Byte *lims[BCJ2_NUM_STREAMS];
+ Byte *dest;
+ const Byte *destLim;
+
+ unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */
+
+ UInt32 ip;
+ Byte temp[4];
+ UInt32 range;
+ UInt32 code;
+ UInt16 probs[2 + 256];
+} CBcj2Dec;
+
+void Bcj2Dec_Init(CBcj2Dec *p);
+
+/* Returns: SZ_OK or SZ_ERROR_DATA */
+SRes Bcj2Dec_Decode(CBcj2Dec *p);
+
+#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0)
+
+
+
+typedef enum
+{
+ BCJ2_ENC_FINISH_MODE_CONTINUE,
+ BCJ2_ENC_FINISH_MODE_END_BLOCK,
+ BCJ2_ENC_FINISH_MODE_END_STREAM
+} EBcj2Enc_FinishMode;
+
+typedef struct
+{
+ Byte *bufs[BCJ2_NUM_STREAMS];
+ const Byte *lims[BCJ2_NUM_STREAMS];
+ const Byte *src;
+ const Byte *srcLim;
+
+ unsigned state;
+ EBcj2Enc_FinishMode finishMode;
+
+ Byte prevByte;
+
+ Byte cache;
+ UInt32 range;
+ UInt64 low;
+ UInt64 cacheSize;
+
+ UInt32 ip;
+
+ /* 32-bit ralative offset in JUMP/CALL commands is
+ - (mod 4 GB) in 32-bit mode
+ - signed Int32 in 64-bit mode
+ We use (mod 4 GB) check for fileSize.
+ Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */
+ UInt32 fileIp;
+ UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */
+ UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */
+
+ UInt32 tempTarget;
+ unsigned tempPos;
+ Byte temp[4 * 2];
+
+ unsigned flushPos;
+
+ UInt16 probs[2 + 256];
+} CBcj2Enc;
+
+void Bcj2Enc_Init(CBcj2Enc *p);
+void Bcj2Enc_Encode(CBcj2Enc *p);
+
+#define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos)
+#define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5)
+
+
+#define BCJ2_RELAT_LIMIT_NUM_BITS 26
+#define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS)
+
+/* limit for CBcj2Enc::fileSize variable */
+#define BCJ2_FileSize_MAX ((UInt32)1 << 31)
+
+EXTERN_C_END
#endif
diff --git a/lzma/C/Bra.c b/lzma/C/Bra.c
index 2a0f147b2e..976810c96e 100644
--- a/lzma/C/Bra.c
+++ b/lzma/C/Bra.c
@@ -1,6 +1,8 @@
/* Bra.c -- Converters for RISC code
2010-04-16 : Igor Pavlov : Public domain */
+#include "Precomp.h"
+
#include "Bra.h"
SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
diff --git a/lzma/C/Bra.h b/lzma/C/Bra.h
index 9c91e332d4..aba8dce14f 100644
--- a/lzma/C/Bra.h
+++ b/lzma/C/Bra.h
@@ -1,14 +1,12 @@
/* Bra.h -- Branch converters for executables
-2009-02-07 : Igor Pavlov : Public domain */
+2013-01-18 : Igor Pavlov : Public domain */
#ifndef __BRA_H
#define __BRA_H
-#include "Types.h"
+#include "7zTypes.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
+EXTERN_C_BEGIN
/*
These functions convert relative addresses to absolute addresses
@@ -61,8 +59,6 @@ SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
-#ifdef __cplusplus
-}
-#endif
+EXTERN_C_END
#endif
diff --git a/lzma/C/Bra86.c b/lzma/C/Bra86.c
index 93566cb212..8dd3ed48d9 100644
--- a/lzma/C/Bra86.c
+++ b/lzma/C/Bra86.c
@@ -1,85 +1,82 @@
/* Bra86.c -- Converter for x86 code (BCJ)
-2008-10-04 : Igor Pavlov : Public domain */
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include "Bra.h"
-#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
-
-const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
-const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
+#define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0)
SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
{
- SizeT bufferPos = 0, prevPosT;
- UInt32 prevMask = *state & 0x7;
+ SizeT pos = 0;
+ UInt32 mask = *state & 7;
if (size < 5)
return 0;
+ size -= 4;
ip += 5;
- prevPosT = (SizeT)0 - 1;
for (;;)
{
- Byte *p = data + bufferPos;
- Byte *limit = data + size - 4;
+ Byte *p = data + pos;
+ const Byte *limit = data + size;
for (; p < limit; p++)
if ((*p & 0xFE) == 0xE8)
break;
- bufferPos = (SizeT)(p - data);
- if (p >= limit)
- break;
- prevPosT = bufferPos - prevPosT;
- if (prevPosT > 3)
- prevMask = 0;
- else
+
{
- prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
- if (prevMask != 0)
+ SizeT d = (SizeT)(p - data - pos);
+ pos = (SizeT)(p - data);
+ if (p >= limit)
{
- Byte b = p[4 - kMaskToBitNumber[prevMask]];
- if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b))
+ *state = (d > 2 ? 0 : mask >> (unsigned)d);
+ return pos;
+ }
+ if (d > 2)
+ mask = 0;
+ else
+ {
+ mask >>= (unsigned)d;
+ if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(mask >> 1) + 1])))
{
- prevPosT = bufferPos;
- prevMask = ((prevMask << 1) & 0x7) | 1;
- bufferPos++;
+ mask = (mask >> 1) | 4;
+ pos++;
continue;
}
}
}
- prevPosT = bufferPos;
if (Test86MSByte(p[4]))
{
- UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
- UInt32 dest;
- for (;;)
+ UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
+ UInt32 cur = ip + (UInt32)pos;
+ pos += 5;
+ if (encoding)
+ v += cur;
+ else
+ v -= cur;
+ if (mask != 0)
{
- Byte b;
- int index;
- if (encoding)
- dest = (ip + (UInt32)bufferPos) + src;
- else
- dest = src - (ip + (UInt32)bufferPos);
- if (prevMask == 0)
- break;
- index = kMaskToBitNumber[prevMask] * 8;
- b = (Byte)(dest >> (24 - index));
- if (!Test86MSByte(b))
- break;
- src = dest ^ ((1 << (32 - index)) - 1);
+ unsigned sh = (mask & 6) << 2;
+ if (Test86MSByte((Byte)(v >> sh)))
+ {
+ v ^= (((UInt32)0x100 << sh) - 1);
+ if (encoding)
+ v += cur;
+ else
+ v -= cur;
+ }
+ mask = 0;
}
- p[4] = (Byte)(~(((dest >> 24) & 1) - 1));
- p[3] = (Byte)(dest >> 16);
- p[2] = (Byte)(dest >> 8);
- p[1] = (Byte)dest;
- bufferPos += 5;
+ p[1] = (Byte)v;
+ p[2] = (Byte)(v >> 8);
+ p[3] = (Byte)(v >> 16);
+ p[4] = (Byte)(0 - ((v >> 24) & 1));
}
else
{
- prevMask = ((prevMask << 1) & 0x7) | 1;
- bufferPos++;
+ mask = (mask >> 1) | 4;
+ pos++;
}
}
- prevPosT = bufferPos - prevPosT;
- *state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
- return bufferPos;
}
diff --git a/lzma/C/BraIA64.c b/lzma/C/BraIA64.c
new file mode 100644
index 0000000000..813830c79d
--- /dev/null
+++ b/lzma/C/BraIA64.c
@@ -0,0 +1,69 @@
+/* BraIA64.c -- Converter for IA-64 code
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+
+static const Byte kBranchTable[32] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0
+};
+
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 16)
+ return 0;
+ size -= 16;
+ for (i = 0; i <= size; i += 16)
+ {
+ UInt32 instrTemplate = data[i] & 0x1F;
+ UInt32 mask = kBranchTable[instrTemplate];
+ UInt32 bitPos = 5;
+ int slot;
+ for (slot = 0; slot < 3; slot++, bitPos += 41)
+ {
+ UInt32 bytePos, bitRes;
+ UInt64 instruction, instNorm;
+ int j;
+ if (((mask >> slot) & 1) == 0)
+ continue;
+ bytePos = (bitPos >> 3);
+ bitRes = bitPos & 0x7;
+ instruction = 0;
+ for (j = 0; j < 6; j++)
+ instruction += (UInt64)data[i + j + bytePos] << (8 * j);
+
+ instNorm = instruction >> bitRes;
+ if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0)
+ {
+ UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF);
+ UInt32 dest;
+ src |= ((UInt32)(instNorm >> 36) & 1) << 20;
+
+ src <<= 4;
+
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+
+ dest >>= 4;
+
+ instNorm &= ~((UInt64)(0x8FFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0xFFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20));
+
+ instruction &= (1 << bitRes) - 1;
+ instruction |= (instNorm << bitRes);
+ for (j = 0; j < 6; j++)
+ data[i + j + bytePos] = (Byte)(instruction >> (8 * j));
+ }
+ }
+ }
+ return i;
+}
diff --git a/lzma/C/Compiler.h b/lzma/C/Compiler.h
new file mode 100644
index 0000000000..de8fab3749
--- /dev/null
+++ b/lzma/C/Compiler.h
@@ -0,0 +1,32 @@
+/* Compiler.h
+2015-08-02 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_COMPILER_H
+#define __7Z_COMPILER_H
+
+#ifdef _MSC_VER
+
+ #ifdef UNDER_CE
+ #define RPC_NO_WINDOWS_H
+ /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */
+ #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
+ #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
+ #endif
+
+ #if _MSC_VER >= 1300
+ #pragma warning(disable : 4996) // This function or variable may be unsafe
+ #else
+ #pragma warning(disable : 4511) // copy constructor could not be generated
+ #pragma warning(disable : 4512) // assignment operator could not be generated
+ #pragma warning(disable : 4514) // unreferenced inline function has been removed
+ #pragma warning(disable : 4702) // unreachable code
+ #pragma warning(disable : 4710) // not inlined
+ #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information
+ #endif
+
+#endif
+
+#define UNUSED_VAR(x) (void)x;
+/* #define UNUSED_VAR(x) x=x; */
+
+#endif
diff --git a/lzma/C/CpuArch.c b/lzma/C/CpuArch.c
index d6ab3f7f83..bcb84cb2bc 100644
--- a/lzma/C/CpuArch.c
+++ b/lzma/C/CpuArch.c
@@ -1,5 +1,7 @@
/* CpuArch.c -- CPU specific code
-2010-10-26: Igor Pavlov : Public domain */
+2015-03-25: Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include "CpuArch.h"
@@ -9,6 +11,10 @@
#define USE_ASM
#endif
+#if !defined(USE_ASM) && _MSC_VER >= 1500
+#include
+#endif
+
#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
static UInt32 CheckFlag(UInt32 flag)
{
@@ -48,7 +54,7 @@ static UInt32 CheckFlag(UInt32 flag)
#define CHECK_CPUID_IS_SUPPORTED
#endif
-static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
+void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
{
#ifdef USE_ASM
@@ -70,28 +76,20 @@ static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
*c = c2;
*d = d2;
- #elif defined __PIC__ && defined __i386__
-
- /* GCC or Clang WITH position-independent code generation, i386 only */
-
- __asm__ __volatile__ (
- "xchgl %%ebx, %1\n"
- "cpuid\n"
- "xchgl %%ebx, %1\n"
- : "=a" (*a) ,
- "=r" (*b) ,
- "=c" (*c) ,
- "=d" (*d)
- : "0" (function)) ;
-
#else
- /* GCC or Clang WITHOUT position-independent code generation, or x86_64 */
-
__asm__ __volatile__ (
+ #if defined(MY_CPU_X86) && defined(__PIC__)
+ "mov %%ebx, %%edi;"
+ "cpuid;"
+ "xchgl %%ebx, %%edi;"
+ : "=a" (*a) ,
+ "=D" (*b) ,
+ #else
"cpuid"
: "=a" (*a) ,
"=b" (*b) ,
+ #endif
"=c" (*c) ,
"=d" (*d)
: "0" (function)) ;
@@ -118,7 +116,7 @@ Bool x86cpuid_CheckAndRead(Cx86cpuid *p)
return True;
}
-static UInt32 kVendors[][3] =
+static const UInt32 kVendors[][3] =
{
{ 0x756E6547, 0x49656E69, 0x6C65746E},
{ 0x68747541, 0x69746E65, 0x444D4163},
@@ -146,12 +144,22 @@ Bool CPU_Is_InOrder()
UInt32 family, model;
if (!x86cpuid_CheckAndRead(&p))
return True;
- family = x86cpuid_GetFamily(&p);
- model = x86cpuid_GetModel(&p);
+
+ family = x86cpuid_GetFamily(p.ver);
+ model = x86cpuid_GetModel(p.ver);
+
firm = x86cpuid_GetFirm(&p);
+
switch (firm)
{
- case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C));
+ case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
+ /* In-Order Atom CPU */
+ model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
+ || model == 0x26 /* 45 nm, Z6xx */
+ || model == 0x27 /* 32 nm, Z2460 */
+ || model == 0x35 /* 32 nm, Z2760 */
+ || model == 0x36 /* 32 nm, N2xxx, D2xxx */
+ )));
case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
}
@@ -159,6 +167,7 @@ Bool CPU_Is_InOrder()
}
#if !defined(MY_CPU_AMD64) && defined(_WIN32)
+#include
static Bool CPU_Sys_Is_SSE_Supported()
{
OSVERSIONINFO vi;
diff --git a/lzma/C/CpuArch.h b/lzma/C/CpuArch.h
index 1cd7c29c5d..b31c2546c0 100644
--- a/lzma/C/CpuArch.h
+++ b/lzma/C/CpuArch.h
@@ -1,27 +1,34 @@
/* CpuArch.h -- CPU specific code
-2010-12-01: Igor Pavlov : Public domain */
+2015-12-01: Igor Pavlov : Public domain */
#ifndef __CPU_ARCH_H
#define __CPU_ARCH_H
-#include "Types.h"
+#include "7zTypes.h"
EXTERN_C_BEGIN
/*
MY_CPU_LE means that CPU is LITTLE ENDIAN.
-If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN).
+MY_CPU_BE means that CPU is BIG ENDIAN.
+If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
-If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform.
*/
-#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
-#define MY_CPU_AMD64
+#if defined(_M_X64) \
+ || defined(_M_AMD64) \
+ || defined(__x86_64__) \
+ || defined(__AMD64__) \
+ || defined(__amd64__)
+ #define MY_CPU_AMD64
#endif
-#if defined(MY_CPU_AMD64) || defined(_M_IA64)
-#define MY_CPU_64BIT
+#if defined(MY_CPU_AMD64) \
+ || defined(_M_IA64) \
+ || defined(__AARCH64EL__) \
+ || defined(__AARCH64EB__)
+ #define MY_CPU_64BIT
#endif
#if defined(_M_IX86) || defined(__i386__)
@@ -32,8 +39,13 @@ If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of pla
#define MY_CPU_X86_OR_AMD64
#endif
-#if defined(MY_CPU_X86) || defined(_M_ARM)
-#define MY_CPU_32BIT
+#if defined(MY_CPU_X86) \
+ || defined(_M_ARM) \
+ || defined(__ARMEL__) \
+ || defined(__THUMBEL__) \
+ || defined(__ARMEB__) \
+ || defined(__THUMBEB__)
+ #define MY_CPU_32BIT
#endif
#if defined(_WIN32) && defined(_M_ARM)
@@ -44,34 +56,63 @@ If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of pla
#define MY_CPU_IA64_LE
#endif
-#if defined(MY_CPU_X86_OR_AMD64)
-#define MY_CPU_LE_UNALIGN
+#if defined(MY_CPU_X86_OR_AMD64) \
+ || defined(MY_CPU_ARM_LE) \
+ || defined(MY_CPU_IA64_LE) \
+ || defined(__LITTLE_ENDIAN__) \
+ || defined(__ARMEL__) \
+ || defined(__THUMBEL__) \
+ || defined(__AARCH64EL__) \
+ || defined(__MIPSEL__) \
+ || defined(__MIPSEL) \
+ || defined(_MIPSEL) \
+ || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+ #define MY_CPU_LE
#endif
-#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__)
-#define MY_CPU_LE
-#endif
-
-#if defined(__BIG_ENDIAN__) || defined(__m68k__) || defined(__ARMEB__) || defined(__MIPSEB__)
-#define MY_CPU_BE
+#if defined(__BIG_ENDIAN__) \
+ || defined(__ARMEB__) \
+ || defined(__THUMBEB__) \
+ || defined(__AARCH64EB__) \
+ || defined(__MIPSEB__) \
+ || defined(__MIPSEB) \
+ || defined(_MIPSEB) \
+ || defined(__m68k__) \
+ || defined(__s390__) \
+ || defined(__s390x__) \
+ || defined(__zarch__) \
+ || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
+ #define MY_CPU_BE
#endif
#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
Stop_Compiling_Bad_Endian
#endif
+
+#ifdef MY_CPU_LE
+ #if defined(MY_CPU_X86_OR_AMD64) \
+ /* || defined(__AARCH64EL__) */
+ #define MY_CPU_LE_UNALIGN
+ #endif
+#endif
+
+
#ifdef MY_CPU_LE_UNALIGN
-#define GetUi16(p) (*(const UInt16 *)(p))
-#define GetUi32(p) (*(const UInt32 *)(p))
-#define GetUi64(p) (*(const UInt64 *)(p))
-#define SetUi16(p, d) *(UInt16 *)(p) = (d);
-#define SetUi32(p, d) *(UInt32 *)(p) = (d);
-#define SetUi64(p, d) *(UInt64 *)(p) = (d);
+#define GetUi16(p) (*(const UInt16 *)(const void *)(p))
+#define GetUi32(p) (*(const UInt32 *)(const void *)(p))
+#define GetUi64(p) (*(const UInt64 *)(const void *)(p))
+
+#define SetUi16(p, v) { *(UInt16 *)(p) = (v); }
+#define SetUi32(p, v) { *(UInt32 *)(p) = (v); }
+#define SetUi64(p, v) { *(UInt64 *)(p) = (v); }
#else
-#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8))
+#define GetUi16(p) ( (UInt16) ( \
+ ((const Byte *)(p))[0] | \
+ ((UInt16)((const Byte *)(p))[1] << 8) ))
#define GetUi32(p) ( \
((const Byte *)(p))[0] | \
@@ -81,29 +122,43 @@ Stop_Compiling_Bad_Endian
#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
-#define SetUi16(p, d) { UInt32 _x_ = (d); \
- ((Byte *)(p))[0] = (Byte)_x_; \
- ((Byte *)(p))[1] = (Byte)(_x_ >> 8); }
+#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)_vvv_; \
+ _ppp_[1] = (Byte)(_vvv_ >> 8); }
-#define SetUi32(p, d) { UInt32 _x_ = (d); \
- ((Byte *)(p))[0] = (Byte)_x_; \
- ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \
- ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
- ((Byte *)(p))[3] = (Byte)(_x_ >> 24); }
+#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)_vvv_; \
+ _ppp_[1] = (Byte)(_vvv_ >> 8); \
+ _ppp_[2] = (Byte)(_vvv_ >> 16); \
+ _ppp_[3] = (Byte)(_vvv_ >> 24); }
-#define SetUi64(p, d) { UInt64 _x64_ = (d); \
- SetUi32(p, (UInt32)_x64_); \
- SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
+#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
+ SetUi32(_ppp2_ , (UInt32)_vvv2_); \
+ SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); }
#endif
-#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)
+
+#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300)
+
+/* Note: we use bswap instruction, that is unsupported in 386 cpu */
+
+#include
#pragma intrinsic(_byteswap_ulong)
#pragma intrinsic(_byteswap_uint64)
#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
+#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v)
+
+#elif defined(MY_CPU_LE_UNALIGN) && defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+
+#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p))
+
+#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v)
+
#else
#define GetBe32(p) ( \
@@ -114,9 +169,19 @@ Stop_Compiling_Bad_Endian
#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
+#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)(_vvv_ >> 24); \
+ _ppp_[1] = (Byte)(_vvv_ >> 16); \
+ _ppp_[2] = (Byte)(_vvv_ >> 8); \
+ _ppp_[3] = (Byte)_vvv_; }
+
#endif
-#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])
+
+#define GetBe16(p) ( (UInt16) ( \
+ ((UInt16)((const Byte *)(p))[0] << 8) | \
+ ((const Byte *)(p))[1] ))
+
#ifdef MY_CPU_X86_OR_AMD64
@@ -138,12 +203,14 @@ enum
CPU_FIRM_VIA
};
+void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);
+
Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
int x86cpuid_GetFirm(const Cx86cpuid *p);
-#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F)
-#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F)
-#define x86cpuid_GetStepping(p) ((p)->ver & 0xF)
+#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF))
+#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF))
+#define x86cpuid_GetStepping(ver) (ver & 0xF)
Bool CPU_Is_InOrder();
Bool CPU_Is_Aes_Supported();
diff --git a/lzma/C/Delta.c b/lzma/C/Delta.c
new file mode 100644
index 0000000000..6cbbe46012
--- /dev/null
+++ b/lzma/C/Delta.c
@@ -0,0 +1,64 @@
+/* Delta.c -- Delta converter
+2009-05-26 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Delta.h"
+
+void Delta_Init(Byte *state)
+{
+ unsigned i;
+ for (i = 0; i < DELTA_STATE_SIZE; i++)
+ state[i] = 0;
+}
+
+static void MyMemCpy(Byte *dest, const Byte *src, unsigned size)
+{
+ unsigned i;
+ for (i = 0; i < size; i++)
+ dest[i] = src[i];
+}
+
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+ Byte buf[DELTA_STATE_SIZE];
+ unsigned j = 0;
+ MyMemCpy(buf, state, delta);
+ {
+ SizeT i;
+ for (i = 0; i < size;)
+ {
+ for (j = 0; j < delta && i < size; i++, j++)
+ {
+ Byte b = data[i];
+ data[i] = (Byte)(b - buf[j]);
+ buf[j] = b;
+ }
+ }
+ }
+ if (j == delta)
+ j = 0;
+ MyMemCpy(state, buf + j, delta - j);
+ MyMemCpy(state + delta - j, buf, j);
+}
+
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+ Byte buf[DELTA_STATE_SIZE];
+ unsigned j = 0;
+ MyMemCpy(buf, state, delta);
+ {
+ SizeT i;
+ for (i = 0; i < size;)
+ {
+ for (j = 0; j < delta && i < size; i++, j++)
+ {
+ buf[j] = data[i] = (Byte)(buf[j] + data[i]);
+ }
+ }
+ }
+ if (j == delta)
+ j = 0;
+ MyMemCpy(state, buf + j, delta - j);
+ MyMemCpy(state + delta - j, buf, j);
+}
diff --git a/lzma/C/Delta.h b/lzma/C/Delta.h
new file mode 100644
index 0000000000..e59d5a252b
--- /dev/null
+++ b/lzma/C/Delta.h
@@ -0,0 +1,19 @@
+/* Delta.h -- Delta converter
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __DELTA_H
+#define __DELTA_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define DELTA_STATE_SIZE 256
+
+void Delta_Init(Byte *state);
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size);
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/LzFind.c b/lzma/C/LzFind.c
index f6c9e66d57..c335d363ce 100644
--- a/lzma/C/LzFind.c
+++ b/lzma/C/LzFind.c
@@ -1,5 +1,7 @@
/* LzFind.c -- Match finder for LZ algorithms
-2009-04-22 : Igor Pavlov : Public domain */
+2015-10-15 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include
@@ -9,8 +11,8 @@
#define kEmptyHashValue 0
#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
-#define kNormalizeMask (~(kNormalizeStepMin - 1))
-#define kMaxHistorySize ((UInt32)3 << 30)
+#define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1))
+#define kMaxHistorySize ((UInt32)7 << 29)
#define kStartMaxLen 3
@@ -19,7 +21,7 @@ static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
if (!p->directInput)
{
alloc->Free(alloc, p->bufferBase);
- p->bufferBase = 0;
+ p->bufferBase = NULL;
}
}
@@ -33,17 +35,16 @@ static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *a
p->blockSize = blockSize;
return 1;
}
- if (p->bufferBase == 0 || p->blockSize != blockSize)
+ if (!p->bufferBase || p->blockSize != blockSize)
{
LzInWindow_Free(p, alloc);
p->blockSize = blockSize;
p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
}
- return (p->bufferBase != 0);
+ return (p->bufferBase != NULL);
}
Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
-Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
@@ -58,9 +59,12 @@ static void MatchFinder_ReadBlock(CMatchFinder *p)
{
if (p->streamEndWasReached || p->result != SZ_OK)
return;
+
+ /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */
+
if (p->directInput)
{
- UInt32 curSize = 0xFFFFFFFF - p->streamPos;
+ UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos);
if (curSize > p->directInputRem)
curSize = (UInt32)p->directInputRem;
p->directInputRem -= curSize;
@@ -69,12 +73,14 @@ static void MatchFinder_ReadBlock(CMatchFinder *p)
p->streamEndWasReached = 1;
return;
}
+
for (;;)
{
Byte *dest = p->buffer + (p->streamPos - p->pos);
size_t size = (p->bufferBase + p->blockSize - dest);
if (size == 0)
return;
+
p->result = p->stream->Read(p->stream, dest, &size);
if (p->result != SZ_OK)
return;
@@ -92,8 +98,8 @@ static void MatchFinder_ReadBlock(CMatchFinder *p)
void MatchFinder_MoveBlock(CMatchFinder *p)
{
memmove(p->bufferBase,
- p->buffer - p->keepSizeBefore,
- (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
+ p->buffer - p->keepSizeBefore,
+ (size_t)(p->streamPos - p->pos) + p->keepSizeBefore);
p->buffer = p->bufferBase + p->keepSizeBefore;
}
@@ -133,15 +139,15 @@ static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
void MatchFinder_Construct(CMatchFinder *p)
{
UInt32 i;
- p->bufferBase = 0;
+ p->bufferBase = NULL;
p->directInput = 0;
- p->hash = 0;
+ p->hash = NULL;
MatchFinder_SetDefaultSettings(p);
for (i = 0; i < 256; i++)
{
UInt32 r = i;
- int j;
+ unsigned j;
for (j = 0; j < 8; j++)
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
p->crc[i] = r;
@@ -151,7 +157,7 @@ void MatchFinder_Construct(CMatchFinder *p)
static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
{
alloc->Free(alloc, p->hash);
- p->hash = 0;
+ p->hash = NULL;
}
void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
@@ -160,11 +166,11 @@ void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
LzInWindow_Free(p, alloc);
}
-static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
+static CLzRef* AllocRefs(size_t num, ISzAlloc *alloc)
{
size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
if (sizeInBytes / sizeof(CLzRef) != num)
- return 0;
+ return NULL;
return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
}
@@ -173,19 +179,24 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
ISzAlloc *alloc)
{
UInt32 sizeReserv;
+
if (historySize > kMaxHistorySize)
{
MatchFinder_Free(p, alloc);
return 0;
}
+
sizeReserv = historySize >> 1;
- if (historySize > ((UInt32)2 << 30))
- sizeReserv = historySize >> 2;
+ if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3;
+ else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2;
+
sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
+
/* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
+
if (LzInWindow_Create(p, sizeReserv, alloc))
{
UInt32 newCyclicBufferSize = historySize + 1;
@@ -210,6 +221,7 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
hs = (1 << 24) - 1;
else
hs >>= 1;
+ /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
}
}
p->hashMask = hs;
@@ -221,24 +233,32 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
}
{
- UInt32 prevSize = p->hashSizeSum + p->numSons;
- UInt32 newSize;
+ size_t newSize;
+ size_t numSons;
p->historySize = historySize;
p->hashSizeSum = hs;
p->cyclicBufferSize = newCyclicBufferSize;
- p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
- newSize = p->hashSizeSum + p->numSons;
- if (p->hash != 0 && prevSize == newSize)
+
+ numSons = newCyclicBufferSize;
+ if (p->btMode)
+ numSons <<= 1;
+ newSize = hs + numSons;
+
+ if (p->hash && p->numRefs == newSize)
return 1;
+
MatchFinder_FreeThisClassMemory(p, alloc);
+ p->numRefs = newSize;
p->hash = AllocRefs(newSize, alloc);
- if (p->hash != 0)
+
+ if (p->hash)
{
p->son = p->hash + p->hashSizeSum;
return 1;
}
}
}
+
MatchFinder_Free(p, alloc);
return 0;
}
@@ -247,9 +267,11 @@ static void MatchFinder_SetLimits(CMatchFinder *p)
{
UInt32 limit = kMaxValForNormalize - p->pos;
UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
+
if (limit2 < limit)
limit = limit2;
limit2 = p->streamPos - p->pos;
+
if (limit2 <= p->keepSizeAfter)
{
if (limit2 > 0)
@@ -257,8 +279,10 @@ static void MatchFinder_SetLimits(CMatchFinder *p)
}
else
limit2 -= p->keepSizeAfter;
+
if (limit2 < limit)
limit = limit2;
+
{
UInt32 lenLimit = p->streamPos - p->pos;
if (lenLimit > p->matchMaxLen)
@@ -268,28 +292,39 @@ static void MatchFinder_SetLimits(CMatchFinder *p)
p->posLimit = p->pos + limit;
}
-void MatchFinder_Init(CMatchFinder *p)
+void MatchFinder_Init_2(CMatchFinder *p, int readData)
{
UInt32 i;
- for (i = 0; i < p->hashSizeSum; i++)
- p->hash[i] = kEmptyHashValue;
+ UInt32 *hash = p->hash;
+ UInt32 num = p->hashSizeSum;
+ for (i = 0; i < num; i++)
+ hash[i] = kEmptyHashValue;
+
p->cyclicBufferPos = 0;
p->buffer = p->bufferBase;
p->pos = p->streamPos = p->cyclicBufferSize;
p->result = SZ_OK;
p->streamEndWasReached = 0;
- MatchFinder_ReadBlock(p);
+
+ if (readData)
+ MatchFinder_ReadBlock(p);
+
MatchFinder_SetLimits(p);
}
+void MatchFinder_Init(CMatchFinder *p)
+{
+ MatchFinder_Init_2(p, True);
+}
+
static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
{
return (p->pos - p->historySize - 1) & kNormalizeMask;
}
-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems)
{
- UInt32 i;
+ size_t i;
for (i = 0; i < numItems; i++)
{
UInt32 value = items[i];
@@ -304,7 +339,7 @@ void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
static void MatchFinder_Normalize(CMatchFinder *p)
{
UInt32 subValue = MatchFinder_GetSubValue(p);
- MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
+ MatchFinder_Normalize3(subValue, p->hash, p->numRefs);
MatchFinder_ReduceOffsets(p, subValue);
}
@@ -465,7 +500,7 @@ static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const
static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
#define GET_MATCHES_HEADER2(minLen, ret_op) \
- UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+ UInt32 lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \
lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
cur = p->buffer;
@@ -481,13 +516,20 @@ static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
#define SKIP_FOOTER \
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+#define UPDATE_maxLen { \
+ ptrdiff_t diff = (ptrdiff_t)0 - d2; \
+ const Byte *c = cur + maxLen; \
+ const Byte *lim = cur + lenLimit; \
+ for (; c != lim; c++) if (*(c + diff) != *c) break; \
+ maxLen = (UInt32)(c - cur); }
+
static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
{
UInt32 offset;
GET_MATCHES_HEADER(2)
HASH2_CALC;
- curMatch = p->hash[hashValue];
- p->hash[hashValue] = p->pos;
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
offset = 0;
GET_MATCHES_FOOTER(offset, 1)
}
@@ -497,35 +539,38 @@ UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
UInt32 offset;
GET_MATCHES_HEADER(3)
HASH_ZIP_CALC;
- curMatch = p->hash[hashValue];
- p->hash[hashValue] = p->pos;
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
offset = 0;
GET_MATCHES_FOOTER(offset, 2)
}
static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
{
- UInt32 hash2Value, delta2, maxLen, offset;
+ UInt32 h2, d2, maxLen, offset, pos;
+ UInt32 *hash;
GET_MATCHES_HEADER(3)
HASH3_CALC;
- delta2 = p->pos - p->hash[hash2Value];
- curMatch = p->hash[kFix3HashSize + hashValue];
-
- p->hash[hash2Value] =
- p->hash[kFix3HashSize + hashValue] = p->pos;
+ hash = p->hash;
+ pos = p->pos;
+ d2 = pos - hash[h2];
+
+ curMatch = hash[kFix3HashSize + hv];
+
+ hash[h2] = pos;
+ hash[kFix3HashSize + hv] = pos;
maxLen = 2;
offset = 0;
- if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+
+ if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
{
- for (; maxLen != lenLimit; maxLen++)
- if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
- break;
+ UPDATE_maxLen
distances[0] = maxLen;
- distances[1] = delta2 - 1;
+ distances[1] = d2 - 1;
offset = 2;
if (maxLen == lenLimit)
{
@@ -533,44 +578,51 @@ static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
MOVE_POS_RET;
}
}
+
GET_MATCHES_FOOTER(offset, maxLen)
}
static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
{
- UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ UInt32 h2, h3, d2, d3, maxLen, offset, pos;
+ UInt32 *hash;
GET_MATCHES_HEADER(4)
HASH4_CALC;
- delta2 = p->pos - p->hash[ hash2Value];
- delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
- curMatch = p->hash[kFix4HashSize + hashValue];
-
- p->hash[ hash2Value] =
- p->hash[kFix3HashSize + hash3Value] =
- p->hash[kFix4HashSize + hashValue] = p->pos;
+ hash = p->hash;
+ pos = p->pos;
- maxLen = 1;
+ d2 = pos - hash[ h2];
+ d3 = pos - hash[kFix3HashSize + h3];
+
+ curMatch = hash[kFix4HashSize + hv];
+
+ hash[ h2] = pos;
+ hash[kFix3HashSize + h3] = pos;
+ hash[kFix4HashSize + hv] = pos;
+
+ maxLen = 0;
offset = 0;
- if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+
+ if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
{
distances[0] = maxLen = 2;
- distances[1] = delta2 - 1;
+ distances[1] = d2 - 1;
offset = 2;
}
- if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+
+ if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
{
maxLen = 3;
- distances[offset + 1] = delta3 - 1;
+ distances[offset + 1] = d3 - 1;
offset += 2;
- delta2 = delta3;
+ d2 = d3;
}
+
if (offset != 0)
{
- for (; maxLen != lenLimit; maxLen++)
- if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
- break;
+ UPDATE_maxLen
distances[offset - 2] = maxLen;
if (maxLen == lenLimit)
{
@@ -578,46 +630,131 @@ static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
MOVE_POS_RET;
}
}
+
if (maxLen < 3)
maxLen = 3;
+
GET_MATCHES_FOOTER(offset, maxLen)
}
+/*
+static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(5)
+
+ HASH5_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash[ h2];
+ d3 = pos - hash[kFix3HashSize + h3];
+ d4 = pos - hash[kFix4HashSize + h4];
+
+ curMatch = hash[kFix5HashSize + hv];
+
+ hash[ h2] = pos;
+ hash[kFix3HashSize + h3] = pos;
+ hash[kFix4HashSize + h4] = pos;
+ hash[kFix5HashSize + hv] = pos;
+
+ maxLen = 0;
+ offset = 0;
+
+ if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = d2 - 1;
+ offset = 2;
+ if (*(cur - d2 + 2) == cur[2])
+ distances[0] = maxLen = 3;
+ else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+ {
+ distances[2] = maxLen = 3;
+ distances[3] = d3 - 1;
+ offset = 4;
+ d2 = d3;
+ }
+ }
+ else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+ {
+ distances[0] = maxLen = 3;
+ distances[1] = d3 - 1;
+ offset = 2;
+ d2 = d3;
+ }
+
+ if (d2 != d4 && d4 < p->cyclicBufferSize
+ && *(cur - d4) == *cur
+ && *(cur - d4 + 3) == *(cur + 3))
+ {
+ maxLen = 4;
+ distances[offset + 1] = d4 - 1;
+ offset += 2;
+ d2 = d4;
+ }
+
+ if (offset != 0)
+ {
+ UPDATE_maxLen
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+
+ if (maxLen < 4)
+ maxLen = 4;
+
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+*/
+
static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
{
- UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ UInt32 h2, h3, d2, d3, maxLen, offset, pos;
+ UInt32 *hash;
GET_MATCHES_HEADER(4)
HASH4_CALC;
- delta2 = p->pos - p->hash[ hash2Value];
- delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
- curMatch = p->hash[kFix4HashSize + hashValue];
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash[ h2];
+ d3 = pos - hash[kFix3HashSize + h3];
+
+ curMatch = hash[kFix4HashSize + hv];
- p->hash[ hash2Value] =
- p->hash[kFix3HashSize + hash3Value] =
- p->hash[kFix4HashSize + hashValue] = p->pos;
+ hash[ h2] = pos;
+ hash[kFix3HashSize + h3] = pos;
+ hash[kFix4HashSize + hv] = pos;
- maxLen = 1;
+ maxLen = 0;
offset = 0;
- if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+
+ if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
{
distances[0] = maxLen = 2;
- distances[1] = delta2 - 1;
+ distances[1] = d2 - 1;
offset = 2;
}
- if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+
+ if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
{
maxLen = 3;
- distances[offset + 1] = delta3 - 1;
+ distances[offset + 1] = d3 - 1;
offset += 2;
- delta2 = delta3;
+ d2 = d3;
}
+
if (offset != 0)
{
- for (; maxLen != lenLimit; maxLen++)
- if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
- break;
+ UPDATE_maxLen
distances[offset - 2] = maxLen;
if (maxLen == lenLimit)
{
@@ -625,22 +762,103 @@ static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
MOVE_POS_RET;
}
}
+
if (maxLen < 3)
maxLen = 3;
+
offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
- distances + offset, maxLen) - (distances));
+ distances + offset, maxLen) - (distances));
MOVE_POS_RET
}
+/*
+static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos
+ UInt32 *hash;
+ GET_MATCHES_HEADER(5)
+
+ HASH5_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash[ h2];
+ d3 = pos - hash[kFix3HashSize + h3];
+ d4 = pos - hash[kFix4HashSize + h4];
+
+ curMatch = hash[kFix5HashSize + hv];
+
+ hash[ h2] = pos;
+ hash[kFix3HashSize + h3] = pos;
+ hash[kFix4HashSize + h4] = pos;
+ hash[kFix5HashSize + hv] = pos;
+
+ maxLen = 0;
+ offset = 0;
+
+ if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = d2 - 1;
+ offset = 2;
+ if (*(cur - d2 + 2) == cur[2])
+ distances[0] = maxLen = 3;
+ else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+ {
+ distances[2] = maxLen = 3;
+ distances[3] = d3 - 1;
+ offset = 4;
+ d2 = d3;
+ }
+ }
+ else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+ {
+ distances[0] = maxLen = 3;
+ distances[1] = d3 - 1;
+ offset = 2;
+ d2 = d3;
+ }
+
+ if (d2 != d4 && d4 < p->cyclicBufferSize
+ && *(cur - d4) == *cur
+ && *(cur - d4 + 3) == *(cur + 3))
+ {
+ maxLen = 4;
+ distances[offset + 1] = d4 - 1;
+ offset += 2;
+ d2 = d4;
+ }
+
+ if (offset != 0)
+ {
+ UPDATE_maxLen
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET;
+ }
+ }
+
+ if (maxLen < 4)
+ maxLen = 4;
+
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances + offset, maxLen) - (distances));
+ MOVE_POS_RET
+}
+*/
+
UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
{
UInt32 offset;
GET_MATCHES_HEADER(3)
HASH_ZIP_CALC;
- curMatch = p->hash[hashValue];
- p->hash[hashValue] = p->pos;
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
- distances, 2) - (distances));
+ distances, 2) - (distances));
MOVE_POS_RET
}
@@ -650,8 +868,8 @@ static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
SKIP_HEADER(2)
HASH2_CALC;
- curMatch = p->hash[hashValue];
- p->hash[hashValue] = p->pos;
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
SKIP_FOOTER
}
while (--num != 0);
@@ -663,8 +881,8 @@ void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
SKIP_HEADER(3)
HASH_ZIP_CALC;
- curMatch = p->hash[hashValue];
- p->hash[hashValue] = p->pos;
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
SKIP_FOOTER
}
while (--num != 0);
@@ -674,12 +892,14 @@ static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
do
{
- UInt32 hash2Value;
+ UInt32 h2;
+ UInt32 *hash;
SKIP_HEADER(3)
HASH3_CALC;
- curMatch = p->hash[kFix3HashSize + hashValue];
- p->hash[hash2Value] =
- p->hash[kFix3HashSize + hashValue] = p->pos;
+ hash = p->hash;
+ curMatch = hash[kFix3HashSize + hv];
+ hash[h2] =
+ hash[kFix3HashSize + hv] = p->pos;
SKIP_FOOTER
}
while (--num != 0);
@@ -689,43 +909,90 @@ static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
do
{
- UInt32 hash2Value, hash3Value;
+ UInt32 h2, h3;
+ UInt32 *hash;
SKIP_HEADER(4)
HASH4_CALC;
- curMatch = p->hash[kFix4HashSize + hashValue];
- p->hash[ hash2Value] =
- p->hash[kFix3HashSize + hash3Value] = p->pos;
- p->hash[kFix4HashSize + hashValue] = p->pos;
+ hash = p->hash;
+ curMatch = hash[kFix4HashSize + hv];
+ hash[ h2] =
+ hash[kFix3HashSize + h3] =
+ hash[kFix4HashSize + hv] = p->pos;
SKIP_FOOTER
}
while (--num != 0);
}
+/*
+static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 h2, h3, h4;
+ UInt32 *hash;
+ SKIP_HEADER(5)
+ HASH5_CALC;
+ hash = p->hash;
+ curMatch = hash[kFix5HashSize + hv];
+ hash[ h2] =
+ hash[kFix3HashSize + h3] =
+ hash[kFix4HashSize + h4] =
+ hash[kFix5HashSize + hv] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+*/
+
static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
do
{
- UInt32 hash2Value, hash3Value;
+ UInt32 h2, h3;
+ UInt32 *hash;
SKIP_HEADER(4)
HASH4_CALC;
- curMatch = p->hash[kFix4HashSize + hashValue];
- p->hash[ hash2Value] =
- p->hash[kFix3HashSize + hash3Value] =
- p->hash[kFix4HashSize + hashValue] = p->pos;
+ hash = p->hash;
+ curMatch = hash[kFix4HashSize + hv];
+ hash[ h2] =
+ hash[kFix3HashSize + h3] =
+ hash[kFix4HashSize + hv] = p->pos;
p->son[p->cyclicBufferPos] = curMatch;
MOVE_POS
}
while (--num != 0);
}
+/*
+static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 h2, h3, h4;
+ UInt32 *hash;
+ SKIP_HEADER(5)
+ HASH5_CALC;
+ hash = p->hash;
+ curMatch = p->hash[kFix5HashSize + hv];
+ hash[ h2] =
+ hash[kFix3HashSize + h3] =
+ hash[kFix4HashSize + h4] =
+ hash[kFix5HashSize + hv] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+*/
+
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{
do
{
SKIP_HEADER(3)
HASH_ZIP_CALC;
- curMatch = p->hash[hashValue];
- p->hash[hashValue] = p->pos;
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
p->son[p->cyclicBufferPos] = curMatch;
MOVE_POS
}
@@ -735,13 +1002,22 @@ void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
{
vTable->Init = (Mf_Init_Func)MatchFinder_Init;
- vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
if (!p->btMode)
{
- vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
- vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+ /* if (p->numHashBytes <= 4) */
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+ }
+ /*
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip;
+ }
+ */
}
else if (p->numHashBytes == 2)
{
@@ -753,9 +1029,16 @@ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
}
- else
+ else /* if (p->numHashBytes == 4) */
{
vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
}
+ /*
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip;
+ }
+ */
}
diff --git a/lzma/C/LzFind.h b/lzma/C/LzFind.h
index 7ebdfa4464..2ff6673771 100644
--- a/lzma/C/LzFind.h
+++ b/lzma/C/LzFind.h
@@ -1,14 +1,12 @@
/* LzFind.h -- Match finder for LZ algorithms
-2009-04-22 : Igor Pavlov : Public domain */
+2015-10-15 : Igor Pavlov : Public domain */
#ifndef __LZ_FIND_H
#define __LZ_FIND_H
-#include "Types.h"
+#include "7zTypes.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
+EXTERN_C_BEGIN
typedef UInt32 CLzRef;
@@ -23,6 +21,11 @@ typedef struct _CMatchFinder
UInt32 cyclicBufferPos;
UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+ Byte streamEndWasReached;
+ Byte btMode;
+ Byte bigHash;
+ Byte directInput;
+
UInt32 matchMaxLen;
CLzRef *hash;
CLzRef *son;
@@ -31,30 +34,30 @@ typedef struct _CMatchFinder
Byte *bufferBase;
ISeqInStream *stream;
- int streamEndWasReached;
-
+
UInt32 blockSize;
UInt32 keepSizeBefore;
UInt32 keepSizeAfter;
UInt32 numHashBytes;
- int directInput;
size_t directInputRem;
- int btMode;
- int bigHash;
UInt32 historySize;
UInt32 fixedHashSize;
UInt32 hashSizeSum;
- UInt32 numSons;
SRes result;
UInt32 crc[256];
+ size_t numRefs;
} CMatchFinder;
#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
-#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+#define Inline_MatchFinder_IsFinishedOK(p) \
+ ((p)->streamEndWasReached \
+ && (p)->streamPos == (p)->pos \
+ && (!(p)->directInput || (p)->directInputRem == 0))
+
int MatchFinder_NeedMove(CMatchFinder *p);
Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
void MatchFinder_MoveBlock(CMatchFinder *p);
@@ -70,7 +73,7 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
ISzAlloc *alloc);
void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems);
void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
@@ -84,7 +87,6 @@ Conditions:
*/
typedef void (*Mf_Init_Func)(void *object);
-typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
@@ -93,7 +95,6 @@ typedef void (*Mf_Skip_Func)(void *object, UInt32);
typedef struct _IMatchFinder
{
Mf_Init_Func Init;
- Mf_GetIndexByte_Func GetIndexByte;
Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
Mf_GetMatches_Func GetMatches;
@@ -102,14 +103,15 @@ typedef struct _IMatchFinder
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+void MatchFinder_Init_2(CMatchFinder *p, int readData);
void MatchFinder_Init(CMatchFinder *p);
+
UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+
void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
-#ifdef __cplusplus
-}
-#endif
+EXTERN_C_END
#endif
diff --git a/lzma/C/LzFindMt.c b/lzma/C/LzFindMt.c
index db95590c34..cb61e0953a 100644
--- a/lzma/C/LzFindMt.c
+++ b/lzma/C/LzFindMt.c
@@ -1,11 +1,13 @@
/* LzFindMt.c -- multithreaded Match finder for LZ algorithms
-2009-09-20 : Igor Pavlov : Public domain */
+2015-10-15 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include "LzHash.h"
#include "LzFindMt.h"
-void MtSync_Construct(CMtSync *p)
+static void MtSync_Construct(CMtSync *p)
{
p->wasCreated = False;
p->csWasInitialized = False;
@@ -18,7 +20,7 @@ void MtSync_Construct(CMtSync *p)
Semaphore_Construct(&p->filledSemaphore);
}
-void MtSync_GetNextBlock(CMtSync *p)
+static void MtSync_GetNextBlock(CMtSync *p)
{
if (p->needStart)
{
@@ -46,7 +48,7 @@ void MtSync_GetNextBlock(CMtSync *p)
/* MtSync_StopWriting must be called if Writing was started */
-void MtSync_StopWriting(CMtSync *p)
+static void MtSync_StopWriting(CMtSync *p)
{
UInt32 myNumBlocks = p->numProcessedBlocks;
if (!Thread_WasCreated(&p->thread) || p->needStart)
@@ -69,7 +71,7 @@ void MtSync_StopWriting(CMtSync *p)
p->needStart = True;
}
-void MtSync_Destruct(CMtSync *p)
+static void MtSync_Destruct(CMtSync *p)
{
if (Thread_WasCreated(&p->thread))
{
@@ -97,7 +99,7 @@ void MtSync_Destruct(CMtSync *p)
#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
-static SRes MtSync_Create2(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks)
+static SRes MtSync_Create2(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks)
{
if (p->wasCreated)
return SZ_OK;
@@ -119,7 +121,7 @@ static SRes MtSync_Create2(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void
return SZ_OK;
}
-static SRes MtSync_Create(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks)
+static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks)
{
SRes res = MtSync_Create2(p, startAddress, obj, numBlocks);
if (res != SZ_OK)
@@ -132,20 +134,20 @@ void MtSync_Init(CMtSync *p) { p->needStart = True; }
#define kMtMaxValForNormalize 0xFFFFFFFF
#define DEF_GetHeads2(name, v, action) \
-static void GetHeads ## name(const Byte *p, UInt32 pos, \
-UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \
-{ action; for (; numHeads != 0; numHeads--) { \
-const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } }
+ static void GetHeads ## name(const Byte *p, UInt32 pos, \
+ UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \
+ { action; for (; numHeads != 0; numHeads--) { \
+ const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } }
#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;)
-DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), hashMask = hashMask; crc = crc; )
+DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), UNUSED_VAR(hashMask); UNUSED_VAR(crc); )
DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask)
DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask)
DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask)
/* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */
-void HashThreadFunc(CMatchFinderMt *mt)
+static void HashThreadFunc(CMatchFinderMt *mt)
{
CMtSync *p = &mt->hashSync;
for (;;)
@@ -171,12 +173,12 @@ void HashThreadFunc(CMatchFinderMt *mt)
CriticalSection_Enter(&mt->btSync.cs);
CriticalSection_Enter(&mt->hashSync.cs);
{
- const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf);
- const Byte *afterPtr;
+ const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf);
+ ptrdiff_t offset;
MatchFinder_MoveBlock(mf);
- afterPtr = MatchFinder_GetPointerToCurrentPos(mf);
- mt->pointerToCurPos -= beforePtr - afterPtr;
- mt->buffer -= beforePtr - afterPtr;
+ offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf);
+ mt->pointerToCurPos -= offset;
+ mt->buffer -= offset;
}
CriticalSection_Leave(&mt->btSync.cs);
CriticalSection_Leave(&mt->hashSync.cs);
@@ -190,7 +192,7 @@ void HashThreadFunc(CMatchFinderMt *mt)
{
UInt32 subValue = (mf->pos - mf->historySize - 1);
MatchFinder_ReduceOffsets(mf, subValue);
- MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1);
+ MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1);
}
{
UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;
@@ -215,7 +217,7 @@ void HashThreadFunc(CMatchFinderMt *mt)
}
}
-void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
+static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
{
MtSync_GetNextBlock(&p->hashSync);
p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;
@@ -231,7 +233,7 @@ void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
#define NO_INLINE MY_FAST_CALL
-Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son,
+static Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son,
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes)
{
@@ -308,12 +310,14 @@ Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CL
#endif
-void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
+static void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
{
UInt32 numProcessed = 0;
UInt32 curPos = 2;
UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2);
+
distances[1] = p->hashNumAvail;
+
while (curPos < limit)
{
if (p->hashBufPos == p->hashBufPosLimit)
@@ -322,9 +326,11 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
distances[1] = numProcessed + p->hashNumAvail;
if (p->hashNumAvail >= p->numHashBytes)
continue;
+ distances[0] = curPos + p->hashNumAvail;
+ distances += curPos;
for (; p->hashNumAvail != 0; p->hashNumAvail--)
- distances[curPos++] = 0;
- break;
+ *distances++ = 0;
+ return;
}
{
UInt32 size = p->hashBufPosLimit - p->hashBufPos;
@@ -341,13 +347,14 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
if (size2 < size)
size = size2;
}
+
#ifndef MFMT_GM_INLINE
while (curPos < limit && size-- != 0)
{
UInt32 *startDistances = distances + curPos;
UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++],
- pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
- startDistances + 1, p->numHashBytes - 1) - startDistances);
+ pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
+ startDistances + 1, p->numHashBytes - 1) - startDistances);
*startDistances = num - 1;
curPos += num;
cyclicBufferPos++;
@@ -358,7 +365,7 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
{
UInt32 posRes;
curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
- distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes);
+ distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos), size, &posRes);
p->hashBufPos += posRes - pos;
cyclicBufferPos += posRes - pos;
p->buffer += posRes - pos;
@@ -374,10 +381,11 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
p->cyclicBufferPos = cyclicBufferPos;
}
}
+
distances[0] = curPos;
}
-void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
+static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
{
CMtSync *sync = &p->hashSync;
if (!sync->needStart)
@@ -391,7 +399,7 @@ void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize)
{
UInt32 subValue = p->pos - p->cyclicBufferSize;
- MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2);
+ MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2);
p->pos -= subValue;
}
@@ -430,15 +438,15 @@ void BtThreadFunc(CMatchFinderMt *mt)
void MatchFinderMt_Construct(CMatchFinderMt *p)
{
- p->hashBuf = 0;
+ p->hashBuf = NULL;
MtSync_Construct(&p->hashSync);
MtSync_Construct(&p->btSync);
}
-void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc)
+static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc)
{
alloc->Free(alloc, p->hashBuf);
- p->hashBuf = 0;
+ p->hashBuf = NULL;
}
void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc)
@@ -451,14 +459,15 @@ void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc)
#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
-static unsigned MY_STD_CALL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; }
-static unsigned MY_STD_CALL BtThreadFunc2(void *p)
+static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; }
+static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p)
{
Byte allocaDummy[0x180];
- int i = 0;
+ unsigned i = 0;
for (i = 0; i < 16; i++)
- allocaDummy[i] = (Byte)i;
- BtThreadFunc((CMatchFinderMt *)p);
+ allocaDummy[i] = (Byte)0;
+ if (allocaDummy[0] == 0)
+ BtThreadFunc((CMatchFinderMt *)p);
return 0;
}
@@ -469,10 +478,10 @@ SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddB
p->historySize = historySize;
if (kMtBtBlockSize <= matchMaxLen * 4)
return SZ_ERROR_PARAM;
- if (p->hashBuf == 0)
+ if (!p->hashBuf)
{
p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32));
- if (p->hashBuf == 0)
+ if (!p->hashBuf)
return SZ_ERROR_MEM;
p->btBuf = p->hashBuf + kHashBufferSize;
}
@@ -492,8 +501,11 @@ void MatchFinderMt_Init(CMatchFinderMt *p)
CMatchFinder *mf = p->MatchFinder;
p->btBufPos = p->btBufPosLimit = 0;
p->hashBufPos = p->hashBufPosLimit = 0;
- MatchFinder_Init(mf);
- p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf);
+
+ /* Init without data reading. We don't want to read data in this thread */
+ MatchFinder_Init_2(mf, False);
+
+ p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf);
p->btNumAvailBytes = 0;
p->lzPos = p->historySize + 1;
@@ -518,13 +530,13 @@ void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
/* p->MatchFinder->ReleaseStream(); */
}
-void MatchFinderMt_Normalize(CMatchFinderMt *p)
+static void MatchFinderMt_Normalize(CMatchFinderMt *p)
{
MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);
p->lzPos = p->historySize + 1;
}
-void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
+static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
{
UInt32 blockIndex;
MtSync_GetNextBlock(&p->btSync);
@@ -536,34 +548,29 @@ void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
MatchFinderMt_Normalize(p);
}
-const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
+static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
{
return p->pointerToCurPos;
}
#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
-UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
+static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
{
GET_NEXT_BLOCK_IF_REQUIRED;
return p->btNumAvailBytes;
}
-Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index)
+static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
{
- return p->pointerToCurPos[index];
-}
-
-UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
-{
- UInt32 hash2Value, curMatch2;
+ UInt32 h2, curMatch2;
UInt32 *hash = p->hash;
const Byte *cur = p->pointerToCurPos;
UInt32 lzPos = p->lzPos;
MT_HASH2_CALC
- curMatch2 = hash[hash2Value];
- hash[hash2Value] = lzPos;
+ curMatch2 = hash[h2];
+ hash[h2] = lzPos;
if (curMatch2 >= matchMinPos)
if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
@@ -571,23 +578,23 @@ UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
*distances++ = 2;
*distances++ = lzPos - curMatch2 - 1;
}
+
return distances;
}
-UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
{
- UInt32 hash2Value, hash3Value, curMatch2, curMatch3;
+ UInt32 h2, h3, curMatch2, curMatch3;
UInt32 *hash = p->hash;
const Byte *cur = p->pointerToCurPos;
UInt32 lzPos = p->lzPos;
MT_HASH3_CALC
- curMatch2 = hash[ hash2Value];
- curMatch3 = hash[kFix3HashSize + hash3Value];
+ curMatch2 = hash[ h2];
+ curMatch3 = hash[kFix3HashSize + h3];
- hash[ hash2Value] =
- hash[kFix3HashSize + hash3Value] =
- lzPos;
+ hash[ h2] = lzPos;
+ hash[kFix3HashSize + h3] = lzPos;
if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
{
@@ -600,43 +607,45 @@ UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
distances[0] = 2;
distances += 2;
}
+
if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
{
*distances++ = 3;
*distances++ = lzPos - curMatch3 - 1;
}
+
return distances;
}
/*
-UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
{
- UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4;
+ UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4;
UInt32 *hash = p->hash;
const Byte *cur = p->pointerToCurPos;
UInt32 lzPos = p->lzPos;
MT_HASH4_CALC
- curMatch2 = hash[ hash2Value];
- curMatch3 = hash[kFix3HashSize + hash3Value];
- curMatch4 = hash[kFix4HashSize + hash4Value];
+ curMatch2 = hash[ h2];
+ curMatch3 = hash[kFix3HashSize + h3];
+ curMatch4 = hash[kFix4HashSize + h4];
- hash[ hash2Value] =
- hash[kFix3HashSize + hash3Value] =
- hash[kFix4HashSize + hash4Value] =
- lzPos;
+ hash[ h2] = lzPos;
+ hash[kFix3HashSize + h3] = lzPos;
+ hash[kFix4HashSize + h4] = lzPos;
if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
{
distances[1] = lzPos - curMatch2 - 1;
if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
{
- distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
+ distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
return distances + 2;
}
distances[0] = 2;
distances += 2;
}
+
if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
{
distances[1] = lzPos - curMatch3 - 1;
@@ -658,13 +667,14 @@ UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
*distances++ = 4;
*distances++ = lzPos - curMatch4 - 1;
}
+
return distances;
}
*/
#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
-UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+static UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
{
const UInt32 *btBuf = p->btBuf + p->btBufPos;
UInt32 len = *btBuf++;
@@ -682,7 +692,7 @@ UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
return len;
}
-UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+static UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
{
const UInt32 *btBuf = p->btBuf + p->btBufPos;
UInt32 len = *btBuf++;
@@ -690,6 +700,7 @@ UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
if (len == 0)
{
+ /* change for bt5 ! */
if (p->btNumAvailBytes-- >= 4)
len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances));
}
@@ -705,7 +716,7 @@ UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
*distances2++ = *btBuf++;
}
while ((len -= 2) != 0);
- len = (UInt32)(distances2 - (distances));
+ len = (UInt32)(distances2 - (distances));
}
INCREASE_LZ_POS
return len;
@@ -715,41 +726,41 @@ UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0);
-void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
+static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
{
SKIP_HEADER2_MT { p->btNumAvailBytes--;
SKIP_FOOTER_MT
}
-void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
+static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
{
SKIP_HEADER_MT(2)
- UInt32 hash2Value;
+ UInt32 h2;
MT_HASH2_CALC
- hash[hash2Value] = p->lzPos;
+ hash[h2] = p->lzPos;
SKIP_FOOTER_MT
}
-void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
+static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
{
SKIP_HEADER_MT(3)
- UInt32 hash2Value, hash3Value;
+ UInt32 h2, h3;
MT_HASH3_CALC
- hash[kFix3HashSize + hash3Value] =
- hash[ hash2Value] =
+ hash[kFix3HashSize + h3] =
+ hash[ h2] =
p->lzPos;
SKIP_FOOTER_MT
}
/*
-void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
+static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
{
SKIP_HEADER_MT(4)
- UInt32 hash2Value, hash3Value, hash4Value;
+ UInt32 h2, h3, h4;
MT_HASH4_CALC
- hash[kFix4HashSize + hash4Value] =
- hash[kFix3HashSize + hash3Value] =
- hash[ hash2Value] =
+ hash[kFix4HashSize + h4] =
+ hash[kFix3HashSize + h3] =
+ hash[ h2] =
p->lzPos;
SKIP_FOOTER_MT
}
@@ -758,11 +769,11 @@ void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
{
vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
- vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte;
vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
- switch(p->MatchFinder->numHashBytes)
+
+ switch (p->MatchFinder->numHashBytes)
{
case 2:
p->GetHeadsFunc = GetHeads2;
@@ -778,7 +789,6 @@ void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
default:
/* case 4: */
p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4;
- /* p->GetHeadsFunc = GetHeads4; */
p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
break;
diff --git a/lzma/C/LzFindMt.h b/lzma/C/LzFindMt.h
index 17ed237d64..46b6924ad7 100644
--- a/lzma/C/LzFindMt.h
+++ b/lzma/C/LzFindMt.h
@@ -1,5 +1,5 @@
/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
-2009-02-07 : Igor Pavlov : Public domain */
+2015-05-03 : Igor Pavlov : Public domain */
#ifndef __LZ_FIND_MT_H
#define __LZ_FIND_MT_H
@@ -7,9 +7,7 @@
#include "LzFind.h"
#include "Threads.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
+EXTERN_C_BEGIN
#define kMtHashBlockSize (1 << 13)
#define kMtHashNumBlocks (1 << 3)
@@ -77,7 +75,7 @@ typedef struct _CMatchFinderMt
UInt32 matchMaxLen;
UInt32 numHashBytes;
UInt32 pos;
- Byte *buffer;
+ const Byte *buffer;
UInt32 cyclicBufferPos;
UInt32 cyclicBufferSize; /* it must be historySize + 1 */
UInt32 cutValue;
@@ -98,8 +96,6 @@ SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddB
void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable);
void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
-#ifdef __cplusplus
-}
-#endif
+EXTERN_C_END
#endif
diff --git a/lzma/C/LzHash.h b/lzma/C/LzHash.h
index b2f0e3c245..2191444072 100644
--- a/lzma/C/LzHash.h
+++ b/lzma/C/LzHash.h
@@ -1,5 +1,5 @@
/* LzHash.h -- HASH functions for LZ algorithms
-2009-02-07 : Igor Pavlov : Public domain */
+2015-04-12 : Igor Pavlov : Public domain */
#ifndef __LZ_HASH_H
#define __LZ_HASH_H
@@ -12,43 +12,46 @@
#define kFix4HashSize (kHash2Size + kHash3Size)
#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
-#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
+#define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8);
#define HASH3_CALC { \
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
- hash2Value = temp & (kHash2Size - 1); \
- hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+ h2 = temp & (kHash2Size - 1); \
+ hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
#define HASH4_CALC { \
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
- hash2Value = temp & (kHash2Size - 1); \
- hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
- hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
#define HASH5_CALC { \
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
- hash2Value = temp & (kHash2Size - 1); \
- hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
- hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
- hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
- hash4Value &= (kHash4Size - 1); }
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ temp ^= (p->crc[cur[3]] << 5); \
+ h4 = temp & (kHash4Size - 1); \
+ hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; }
-/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
-#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
+/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
+#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
#define MT_HASH2_CALC \
- hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+ h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
#define MT_HASH3_CALC { \
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
- hash2Value = temp & (kHash2Size - 1); \
- hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+ h2 = temp & (kHash2Size - 1); \
+ h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
#define MT_HASH4_CALC { \
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
- hash2Value = temp & (kHash2Size - 1); \
- hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
- hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
#endif
diff --git a/lzma/C/Lzma2Dec.c b/lzma/C/Lzma2Dec.c
index 7c4eb4449e..b6884571c2 100644
--- a/lzma/C/Lzma2Dec.c
+++ b/lzma/C/Lzma2Dec.c
@@ -1,8 +1,10 @@
/* Lzma2Dec.c -- LZMA2 Decoder
-2010-12-15 : Igor Pavlov : Public domain */
+2015-11-09 : Igor Pavlov : Public domain */
/* #define SHOW_DEBUG_INFO */
+#include "Precomp.h"
+
#ifdef SHOW_DEBUG_INFO
#include
#endif
@@ -97,12 +99,12 @@ void Lzma2Dec_Init(CLzma2Dec *p)
static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
{
- switch(p->state)
+ switch (p->state)
{
case LZMA2_STATE_CONTROL:
p->control = b;
- PRF(printf("\n %4X ", p->decoder.dicPos));
- PRF(printf(" %2X", b));
+ PRF(printf("\n %4X ", (unsigned)p->decoder.dicPos));
+ PRF(printf(" %2X", (unsigned)b));
if (p->control == 0)
return LZMA2_STATE_FINISHED;
if (LZMA2_IS_UNCOMPRESSED_STATE(p))
@@ -122,7 +124,7 @@ static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
case LZMA2_STATE_UNPACK1:
p->unpackSize |= (UInt32)b;
p->unpackSize++;
- PRF(printf(" %8d", p->unpackSize));
+ PRF(printf(" %8u", (unsigned)p->unpackSize));
return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0;
case LZMA2_STATE_PACK0:
@@ -132,13 +134,13 @@ static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
case LZMA2_STATE_PACK1:
p->packSize |= (UInt32)b;
p->packSize++;
- PRF(printf(" %8d", p->packSize));
+ PRF(printf(" %8u", (unsigned)p->packSize));
return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP:
(p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA);
case LZMA2_STATE_PROP:
{
- int lc, lp;
+ unsigned lc, lp;
if (b >= (9 * 5 * 5))
return LZMA2_STATE_ERROR;
lc = b % 9;
@@ -177,13 +179,16 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
while (p->state != LZMA2_STATE_FINISHED)
{
SizeT dicPos = p->decoder.dicPos;
+
if (p->state == LZMA2_STATE_ERROR)
return SZ_ERROR_DATA;
+
if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY)
{
*status = LZMA_STATUS_NOT_FINISHED;
return SZ_OK;
}
+
if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
{
if (*srcLen == inSize)
@@ -193,8 +198,15 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
}
(*srcLen)++;
p->state = Lzma2Dec_UpdateState(p, *src++);
+
+ if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED)
+ {
+ p->state = LZMA2_STATE_ERROR;
+ return SZ_ERROR_DATA;
+ }
continue;
}
+
{
SizeT destSizeCur = dicLimit - dicPos;
SizeT srcSizeCur = inSize - *srcLen;
@@ -220,7 +232,10 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
if (initDic)
p->needInitProp = p->needInitState = True;
else if (p->needInitDic)
+ {
+ p->state = LZMA2_STATE_ERROR;
return SZ_ERROR_DATA;
+ }
p->needInitDic = False;
LzmaDec_InitDicAndState(&p->decoder, initDic, False);
}
@@ -229,7 +244,10 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
srcSizeCur = destSizeCur;
if (srcSizeCur == 0)
+ {
+ p->state = LZMA2_STATE_ERROR;
return SZ_ERROR_DATA;
+ }
LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur);
@@ -245,17 +263,21 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
if (p->state == LZMA2_STATE_DATA)
{
- int mode = LZMA2_GET_LZMA_MODE(p);
+ unsigned mode = LZMA2_GET_LZMA_MODE(p);
Bool initDic = (mode == 3);
- Bool initState = (mode > 0);
+ Bool initState = (mode != 0);
if ((!initDic && p->needInitDic) || (!initState && p->needInitState))
+ {
+ p->state = LZMA2_STATE_ERROR;
return SZ_ERROR_DATA;
+ }
LzmaDec_InitDicAndState(&p->decoder, initDic, initState);
p->needInitDic = False;
p->needInitState = False;
p->state = LZMA2_STATE_DATA_CONT;
}
+
if (srcSizeCur > p->packSize)
srcSizeCur = (SizeT)p->packSize;
@@ -274,16 +296,22 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
if (srcSizeCur == 0 && outSizeProcessed == 0)
{
- if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ||
- p->unpackSize != 0 || p->packSize != 0)
+ if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ || p->unpackSize != 0
+ || p->packSize != 0)
+ {
+ p->state = LZMA2_STATE_ERROR;
return SZ_ERROR_DATA;
+ }
p->state = LZMA2_STATE_CONTROL;
}
+
if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
*status = LZMA_STATUS_NOT_FINISHED;
}
}
}
+
*status = LZMA_STATUS_FINISHED_WITH_MARK;
return SZ_OK;
}
diff --git a/lzma/C/Lzma2Dec.h b/lzma/C/Lzma2Dec.h
index 827698deeb..026cdefe99 100644
--- a/lzma/C/Lzma2Dec.h
+++ b/lzma/C/Lzma2Dec.h
@@ -1,14 +1,12 @@
/* Lzma2Dec.h -- LZMA2 Decoder
-2009-05-03 : Igor Pavlov : Public domain */
+2015-05-13 : Igor Pavlov : Public domain */
#ifndef __LZMA2_DEC_H
#define __LZMA2_DEC_H
#include "LzmaDec.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
+EXTERN_C_BEGIN
/* ---------- State Interface ---------- */
@@ -17,7 +15,7 @@ typedef struct
CLzmaDec decoder;
UInt32 packSize;
UInt32 unpackSize;
- int state;
+ unsigned state;
Byte control;
Bool needInitDic;
Bool needInitState;
@@ -77,8 +75,6 @@ Returns:
SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc);
-#ifdef __cplusplus
-}
-#endif
+EXTERN_C_END
#endif
diff --git a/lzma/C/LzmaDec.c b/lzma/C/LzmaDec.c
index 72451d1ffd..651d1f2843 100644
--- a/lzma/C/LzmaDec.c
+++ b/lzma/C/LzmaDec.c
@@ -1,5 +1,7 @@
/* LzmaDec.c -- LZMA Decoder
-2010-12-15 : Igor Pavlov : Public domain */
+2015-06-23 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include "LzmaDec.h"
@@ -44,6 +46,13 @@
i -= 0x40; }
#endif
+#define NORMAL_LITER_DEC GET_BIT(prob + symbol, symbol)
+#define MATCHED_LITER_DEC \
+ matchByte <<= 1; \
+ bit = (matchByte & offs); \
+ probLit = prob + offs + bit + symbol; \
+ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
+
#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
@@ -105,14 +114,14 @@
#define Literal (RepLenCoder + kNumLenProbs)
#define LZMA_BASE_SIZE 1846
-#define LZMA_LIT_SIZE 768
-
-#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+#define LZMA_LIT_SIZE 0x300
#if Literal != LZMA_BASE_SIZE
StopCompilingDueBUG
#endif
+#define LzmaProps_GetNumProbs(p) (Literal + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
#define LZMA_DIC_MIN (1 << 12)
/* First LZMA-symbol is always decoded.
@@ -124,8 +133,8 @@ Out:
p->remainLen:
< kMatchSpecLenStart : normal remain
= kMatchSpecLenStart : finished
- = kMatchSpecLenStart + 1 : Flush marker
- = kMatchSpecLenStart + 2 : State Init Marker
+ = kMatchSpecLenStart + 1 : Flush marker (unused now)
+ = kMatchSpecLenStart + 2 : State Init Marker (unused now)
*/
static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
@@ -163,38 +172,62 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
unsigned symbol;
UPDATE_0(prob);
prob = probs + Literal;
- if (checkDicSize != 0 || processedPos != 0)
- prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
- (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
+ if (processedPos != 0 || checkDicSize != 0)
+ prob += ((UInt32)LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
+ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
+ processedPos++;
if (state < kNumLitStates)
{
state -= (state < 4) ? state : 3;
symbol = 1;
- do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
+ #ifdef _LZMA_SIZE_OPT
+ do { NORMAL_LITER_DEC } while (symbol < 0x100);
+ #else
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ #endif
}
else
{
- unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
unsigned offs = 0x100;
state -= (state < 10) ? 3 : 6;
symbol = 1;
+ #ifdef _LZMA_SIZE_OPT
do
{
unsigned bit;
CLzmaProb *probLit;
- matchByte <<= 1;
- bit = (matchByte & offs);
- probLit = prob + offs + bit + symbol;
- GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
+ MATCHED_LITER_DEC
}
while (symbol < 0x100);
+ #else
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ }
+ #endif
}
+
dic[dicPos++] = (Byte)symbol;
- processedPos++;
continue;
}
- else
+
{
UPDATE_1(prob);
prob = probs + IsRep + state;
@@ -217,7 +250,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
IF_BIT_0(prob)
{
UPDATE_0(prob);
- dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
dicPos++;
processedPos++;
state = state < kNumLitStates ? 9 : 11;
@@ -258,6 +291,8 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
state = state < kNumLitStates ? 8 : 11;
prob = probs + RepLenCoder;
}
+
+ #ifdef _LZMA_SIZE_OPT
{
unsigned limit, offset;
CLzmaProb *probLen = prob + LenChoice;
@@ -290,6 +325,42 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
TREE_DECODE(probLen, limit, len);
len += offset;
}
+ #else
+ {
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ len = 1;
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ len -= 8;
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ len = 1;
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ TREE_DECODE(probLen, (1 << kLenNumHighBits), len);
+ len += kLenNumLowSymbols + kLenNumMidSymbols;
+ }
+ }
+ }
+ #endif
if (state >= kNumStates)
{
@@ -300,7 +371,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
if (distance >= kStartPosModelIndex)
{
unsigned posSlot = (unsigned)distance;
- int numDirectBits = (int)(((distance >> 1) - 1));
+ unsigned numDirectBits = (unsigned)(((distance >> 1) - 1));
distance = (2 | (distance & 1));
if (posSlot < kEndPosModelIndex)
{
@@ -359,6 +430,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
}
}
}
+
rep3 = rep2;
rep2 = rep1;
rep1 = rep0;
@@ -366,26 +438,39 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
if (checkDicSize == 0)
{
if (distance >= processedPos)
+ {
+ p->dicPos = dicPos;
return SZ_ERROR_DATA;
+ }
}
else if (distance >= checkDicSize)
+ {
+ p->dicPos = dicPos;
return SZ_ERROR_DATA;
+ }
state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
}
len += kMatchMinLen;
- if (limit == dicPos)
- return SZ_ERROR_DATA;
{
- SizeT rem = limit - dicPos;
- unsigned curLen = ((rem < len) ? (unsigned)rem : len);
- SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
+ SizeT rem;
+ unsigned curLen;
+ SizeT pos;
+
+ if ((rem = limit - dicPos) == 0)
+ {
+ p->dicPos = dicPos;
+ return SZ_ERROR_DATA;
+ }
+
+ curLen = ((rem < len) ? (unsigned)rem : len);
+ pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);
processedPos += curLen;
len -= curLen;
- if (pos + curLen <= dicBufSize)
+ if (curLen <= dicBufSize - pos)
{
Byte *dest = dic + dicPos;
ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
@@ -409,7 +494,9 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
}
}
while (dicPos < limit && buf < bufLimit);
+
NORMALIZE;
+
p->buf = buf;
p->range = range;
p->code = code;
@@ -433,9 +520,10 @@ static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
SizeT dicPos = p->dicPos;
SizeT dicBufSize = p->dicBufSize;
unsigned len = p->remainLen;
- UInt32 rep0 = p->reps[0];
- if (limit - dicPos < len)
- len = (unsigned)(limit - dicPos);
+ SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */
+ SizeT rem = limit - dicPos;
+ if (rem < len)
+ len = (unsigned)(rem);
if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
p->checkDicSize = p->prop.dicSize;
@@ -445,7 +533,7 @@ static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
while (len != 0)
{
len--;
- dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
dicPos++;
}
p->dicPos = dicPos;
@@ -463,17 +551,19 @@ static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte
if (limit - p->dicPos > rem)
limit2 = p->dicPos + rem;
}
+
RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
- if (p->processedPos >= p->prop.dicSize)
+
+ if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize)
p->checkDicSize = p->prop.dicSize;
+
LzmaDec_WriteRem(p, limit);
}
while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
if (p->remainLen > kMatchSpecLenStart)
- {
p->remainLen = kMatchSpecLenStart;
- }
+
return 0;
}
@@ -490,12 +580,12 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS
UInt32 range = p->range;
UInt32 code = p->code;
const Byte *bufLimit = buf + inSize;
- CLzmaProb *probs = p->probs;
+ const CLzmaProb *probs = p->probs;
unsigned state = p->state;
ELzmaDummy res;
{
- CLzmaProb *prob;
+ const CLzmaProb *prob;
UInt32 bound;
unsigned ttt;
unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
@@ -509,9 +599,9 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS
prob = probs + Literal;
if (p->checkDicSize != 0 || p->processedPos != 0)
- prob += (LZMA_LIT_SIZE *
- ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
- (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
+ prob += ((UInt32)LZMA_LIT_SIZE *
+ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
+ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
if (state < kNumLitStates)
{
@@ -521,13 +611,13 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS
else
{
unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
- ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
+ (p->dicPos < p->reps[0] ? p->dicBufSize : 0)];
unsigned offs = 0x100;
unsigned symbol = 1;
do
{
unsigned bit;
- CLzmaProb *probLit;
+ const CLzmaProb *probLit;
matchByte <<= 1;
bit = (matchByte & offs);
probLit = prob + offs + bit + symbol;
@@ -597,7 +687,7 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS
}
{
unsigned limit, offset;
- CLzmaProb *probLen = prob + LenChoice;
+ const CLzmaProb *probLen = prob + LenChoice;
IF_BIT_0_CHECK(probLen)
{
UPDATE_0_CHECK;
@@ -637,7 +727,7 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS
TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
if (posSlot >= kStartPosModelIndex)
{
- int numDirectBits = ((posSlot >> 1) - 1);
+ unsigned numDirectBits = ((posSlot >> 1) - 1);
/* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
@@ -676,13 +766,6 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS
}
-static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
-{
- p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
- p->range = 0xFFFFFFFF;
- p->needFlush = 0;
-}
-
void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
{
p->needFlush = 1;
@@ -707,8 +790,8 @@ void LzmaDec_Init(CLzmaDec *p)
static void LzmaDec_InitStateReal(CLzmaDec *p)
{
- UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
- UInt32 i;
+ SizeT numProbs = LzmaProps_GetNumProbs(&p->prop);
+ SizeT i;
CLzmaProb *probs = p->probs;
for (i = 0; i < numProbs; i++)
probs[i] = kBitModelTotal >> 1;
@@ -730,7 +813,7 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr
{
int checkEndMarkNow;
- if (p->needFlush != 0)
+ if (p->needFlush)
{
for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
p->tempBuf[p->tempBufSize++] = *src++;
@@ -741,8 +824,13 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr
}
if (p->tempBuf[0] != 0)
return SZ_ERROR_DATA;
-
- LzmaDec_InitRc(p, p->tempBuf);
+ p->code =
+ ((UInt32)p->tempBuf[1] << 24)
+ | ((UInt32)p->tempBuf[2] << 16)
+ | ((UInt32)p->tempBuf[3] << 8)
+ | ((UInt32)p->tempBuf[4]);
+ p->range = 0xFFFFFFFF;
+ p->needFlush = 0;
p->tempBufSize = 0;
}
@@ -826,7 +914,16 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr
p->buf = p->tempBuf;
if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
return SZ_ERROR_DATA;
- lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
+
+ {
+ unsigned kkk = (unsigned)(p->buf - p->tempBuf);
+ if (rem < kkk)
+ return SZ_ERROR_FAIL; /* some internal error */
+ rem -= kkk;
+ if (lookAhead < rem)
+ return SZ_ERROR_FAIL; /* some internal error */
+ lookAhead -= rem;
+ }
(*srcLen) += lookAhead;
src += lookAhead;
inSize -= lookAhead;
@@ -881,13 +978,13 @@ SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *sr
void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
{
alloc->Free(alloc, p->probs);
- p->probs = 0;
+ p->probs = NULL;
}
static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
{
alloc->Free(alloc, p->dic);
- p->dic = 0;
+ p->dic = NULL;
}
void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
@@ -925,12 +1022,12 @@ SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
{
UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
- if (p->probs == 0 || numProbs != p->numProbs)
+ if (!p->probs || numProbs != p->numProbs)
{
LzmaDec_FreeProbs(p, alloc);
p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
p->numProbs = numProbs;
- if (p->probs == 0)
+ if (!p->probs)
return SZ_ERROR_MEM;
}
return SZ_OK;
@@ -951,12 +1048,22 @@ SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAll
SizeT dicBufSize;
RINOK(LzmaProps_Decode(&propNew, props, propsSize));
RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
- dicBufSize = propNew.dicSize;
- if (p->dic == 0 || dicBufSize != p->dicBufSize)
+
+ {
+ UInt32 dictSize = propNew.dicSize;
+ SizeT mask = ((UInt32)1 << 12) - 1;
+ if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1;
+ else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;;
+ dicBufSize = ((SizeT)dictSize + mask) & ~mask;
+ if (dicBufSize < dictSize)
+ dicBufSize = dictSize;
+ }
+
+ if (!p->dic || dicBufSize != p->dicBufSize)
{
LzmaDec_FreeDict(p, alloc);
p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
- if (p->dic == 0)
+ if (!p->dic)
{
LzmaDec_FreeProbs(p, alloc);
return SZ_ERROR_MEM;
diff --git a/lzma/C/LzmaDec.h b/lzma/C/LzmaDec.h
index 6741a644b6..2633abeac9 100644
--- a/lzma/C/LzmaDec.h
+++ b/lzma/C/LzmaDec.h
@@ -1,14 +1,12 @@
/* LzmaDec.h -- LZMA Decoder
-2009-02-07 : Igor Pavlov : Public domain */
+2013-01-18 : Igor Pavlov : Public domain */
#ifndef __LZMA_DEC_H
#define __LZMA_DEC_H
-#include "Types.h"
+#include "7zTypes.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
+EXTERN_C_BEGIN
/* #define _LZMA_PROB32 */
/* _LZMA_PROB32 can increase the speed on some CPUs,
@@ -224,8 +222,6 @@ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
ELzmaStatus *status, ISzAlloc *alloc);
-#ifdef __cplusplus
-}
-#endif
+EXTERN_C_END
#endif
diff --git a/lzma/C/LzmaEnc.c b/lzma/C/LzmaEnc.c
index 870399d35a..11de42c09d 100644
--- a/lzma/C/LzmaEnc.c
+++ b/lzma/C/LzmaEnc.c
@@ -1,5 +1,7 @@
/* LzmaEnc.c -- LZMA Encoder
-2011-01-27 : Igor Pavlov : Public domain */
+2015-11-08 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
#include
@@ -18,9 +20,12 @@
#endif
#ifdef SHOW_STAT
-static int ttt = 0;
+static unsigned g_STAT_OFFSET = 0;
#endif
+#define kMaxHistorySize ((UInt32)3 << 29)
+/* #define kMaxHistorySize ((UInt32)7 << 29) */
+
#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
#define kBlockSize (9 << 10)
@@ -46,7 +51,7 @@ void LzmaEncProps_Init(CLzmaEncProps *p)
{
p->level = 5;
p->dictSize = p->mc = 0;
- p->reduceSize = (UInt32)(Int32)-1;
+ p->reduceSize = (UInt64)(Int64)-1;
p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
p->writeEndMark = 0;
}
@@ -56,24 +61,28 @@ void LzmaEncProps_Normalize(CLzmaEncProps *p)
int level = p->level;
if (level < 0) level = 5;
p->level = level;
+
if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
if (p->dictSize > p->reduceSize)
{
unsigned i;
- for (i = 15; i <= 30; i++)
+ for (i = 11; i <= 30; i++)
{
- if (p->reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; }
- if (p->reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; }
+ if ((UInt32)p->reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; }
+ if ((UInt32)p->reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; }
}
}
+
if (p->lc < 0) p->lc = 3;
if (p->lp < 0) p->lp = 0;
if (p->pb < 0) p->pb = 2;
+
if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
if (p->numHashBytes < 0) p->numHashBytes = 4;
- if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
+ if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
+
if (p->numThreads < 0)
p->numThreads =
#ifndef _7ZIP_ST
@@ -90,17 +99,18 @@ UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
return props.dictSize;
}
+#if (_MSC_VER >= 1400)
+/* BSR code is fast for some new CPUs */
/* #define LZMA_LOG_BSR */
-/* Define it for Intel's CPU */
-
+#endif
#ifdef LZMA_LOG_BSR
-#define kDicLogSizeMaxCompress 30
+#define kDicLogSizeMaxCompress 32
#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
-UInt32 GetPosSlot1(UInt32 pos)
+static UInt32 GetPosSlot1(UInt32 pos)
{
UInt32 res;
BSR2_RET(pos, res);
@@ -111,27 +121,44 @@ UInt32 GetPosSlot1(UInt32 pos)
#else
-#define kNumLogBits (9 + (int)sizeof(size_t) / 2)
+#define kNumLogBits (9 + sizeof(size_t) / 2)
+/* #define kNumLogBits (11 + sizeof(size_t) / 8 * 3) */
+
#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
-void LzmaEnc_FastPosInit(Byte *g_FastPos)
+static void LzmaEnc_FastPosInit(Byte *g_FastPos)
{
- int c = 2, slotFast;
+ unsigned slot;
g_FastPos[0] = 0;
g_FastPos[1] = 1;
+ g_FastPos += 2;
- for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
+ for (slot = 2; slot < kNumLogBits * 2; slot++)
{
- UInt32 k = (1 << ((slotFast >> 1) - 1));
- UInt32 j;
- for (j = 0; j < k; j++, c++)
- g_FastPos[c] = (Byte)slotFast;
+ size_t k = ((size_t)1 << ((slot >> 1) - 1));
+ size_t j;
+ for (j = 0; j < k; j++)
+ g_FastPos[j] = (Byte)slot;
+ g_FastPos += k;
}
}
+/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */
+/*
#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
(0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
res = p->g_FastPos[pos >> i] + (i * 2); }
+*/
+
+/*
+#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
+ (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \
+ res = p->g_FastPos[pos >> i] + (i * 2); }
+*/
+
+#define BSR2_RET(pos, res) { UInt32 i = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \
+ res = p->g_FastPos[pos >> i] + (i * 2); }
+
/*
#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
p->g_FastPos[pos >> 6] + 12 : \
@@ -211,6 +238,7 @@ typedef struct
#define kNumStates 12
+
typedef struct
{
CLzmaProb choice;
@@ -220,14 +248,16 @@ typedef struct
CLzmaProb high[kLenNumHighSymbols];
} CLenEnc;
+
typedef struct
{
CLenEnc p;
- UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
UInt32 tableSize;
+ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
UInt32 counters[LZMA_NUM_PB_STATES_MAX];
} CLenPriceEnc;
+
typedef struct
{
UInt32 range;
@@ -242,10 +272,14 @@ typedef struct
SRes res;
} CRangeEnc;
+
typedef struct
{
CLzmaProb *litProbs;
+ UInt32 state;
+ UInt32 reps[LZMA_NUM_REPS];
+
CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
CLzmaProb isRep[kNumStates];
CLzmaProb isRepG0[kNumStates];
@@ -259,15 +293,49 @@ typedef struct
CLenPriceEnc lenEnc;
CLenPriceEnc repLenEnc;
-
- UInt32 reps[LZMA_NUM_REPS];
- UInt32 state;
} CSaveState;
+
typedef struct
{
- IMatchFinder matchFinder;
void *matchFinderObj;
+ IMatchFinder matchFinder;
+
+ UInt32 optimumEndIndex;
+ UInt32 optimumCurrentIndex;
+
+ UInt32 longestMatchLength;
+ UInt32 numPairs;
+ UInt32 numAvail;
+
+ UInt32 numFastBytes;
+ UInt32 additionalOffset;
+ UInt32 reps[LZMA_NUM_REPS];
+ UInt32 state;
+
+ unsigned lc, lp, pb;
+ unsigned lpMask, pbMask;
+ unsigned lclp;
+
+ CLzmaProb *litProbs;
+
+ Bool fastMode;
+ Bool writeEndMark;
+ Bool finished;
+ Bool multiThread;
+ Bool needInit;
+
+ UInt64 nowPos64;
+
+ UInt32 matchPriceCount;
+ UInt32 alignPriceCount;
+
+ UInt32 distTableSize;
+
+ UInt32 dictSize;
+ SRes result;
+
+ CRangeEnc rc;
#ifndef _7ZIP_ST
Bool mtMode;
@@ -280,12 +348,6 @@ typedef struct
Byte pad[128];
#endif
- UInt32 optimumEndIndex;
- UInt32 optimumCurrentIndex;
-
- UInt32 longestMatchLength;
- UInt32 numPairs;
- UInt32 numAvail;
COptimal opt[kNumOpts];
#ifndef LZMA_LOG_BSR
@@ -294,22 +356,10 @@ typedef struct
UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
- UInt32 numFastBytes;
- UInt32 additionalOffset;
- UInt32 reps[LZMA_NUM_REPS];
- UInt32 state;
UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
UInt32 alignPrices[kAlignTableSize];
- UInt32 alignPriceCount;
-
- UInt32 distTableSize;
-
- unsigned lc, lp, pb;
- unsigned lpMask, pbMask;
-
- CLzmaProb *litProbs;
CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
CLzmaProb isRep[kNumStates];
@@ -325,26 +375,14 @@ typedef struct
CLenPriceEnc lenEnc;
CLenPriceEnc repLenEnc;
- unsigned lclp;
-
- Bool fastMode;
-
- CRangeEnc rc;
-
- Bool writeEndMark;
- UInt64 nowPos64;
- UInt32 matchPriceCount;
- Bool finished;
- Bool multiThread;
-
- SRes result;
- UInt32 dictSize;
-
- int needInit;
-
CSaveState saveState;
+
+ #ifndef _7ZIP_ST
+ Byte pad2[128];
+ #endif
} CLzmaEnc;
+
void LzmaEnc_SaveState(CLzmaEncHandle pp)
{
CLzmaEnc *p = (CLzmaEnc *)pp;
@@ -368,7 +406,7 @@ void LzmaEnc_SaveState(CLzmaEncHandle pp)
memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
memcpy(dest->reps, p->reps, sizeof(p->reps));
- memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
+ memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << p->lclp) * sizeof(CLzmaProb));
}
void LzmaEnc_RestoreState(CLzmaEncHandle pp)
@@ -394,7 +432,7 @@ void LzmaEnc_RestoreState(CLzmaEncHandle pp)
memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
memcpy(dest->reps, p->reps, sizeof(p->reps));
- memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
+ memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << dest->lclp) * sizeof(CLzmaProb));
}
SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
@@ -403,9 +441,13 @@ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
CLzmaEncProps props = *props2;
LzmaEncProps_Normalize(&props);
- if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
- props.dictSize > ((UInt32)1 << kDicLogSizeMaxCompress) || props.dictSize > ((UInt32)1 << 30))
+ if (props.lc > LZMA_LC_MAX
+ || props.lp > LZMA_LP_MAX
+ || props.pb > LZMA_PB_MAX
+ || props.dictSize > ((UInt64)1 << kDicLogSizeMaxCompress)
+ || props.dictSize > kMaxHistorySize)
return SZ_ERROR_PARAM;
+
p->dictSize = props.dictSize;
{
unsigned fb = props.fb;
@@ -419,7 +461,7 @@ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
p->lp = props.lp;
p->pb = props.pb;
p->fastMode = (props.algo == 0);
- p->matchFinderBase.btMode = props.btMode;
+ p->matchFinderBase.btMode = (Byte)(props.btMode ? 1 : 0);
{
UInt32 numHashBytes = 4;
if (props.btMode)
@@ -463,8 +505,8 @@ static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11,
static void RangeEnc_Construct(CRangeEnc *p)
{
- p->outStream = 0;
- p->bufBase = 0;
+ p->outStream = NULL;
+ p->bufBase = NULL;
}
#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
@@ -472,10 +514,10 @@ static void RangeEnc_Construct(CRangeEnc *p)
#define RC_BUF_SIZE (1 << 16)
static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
{
- if (p->bufBase == 0)
+ if (!p->bufBase)
{
p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
- if (p->bufBase == 0)
+ if (!p->bufBase)
return 0;
p->bufLim = p->bufBase + RC_BUF_SIZE;
}
@@ -516,7 +558,7 @@ static void RangeEnc_FlushStream(CRangeEnc *p)
static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
{
- if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0)
+ if ((UInt32)p->low < (UInt32)0xFF000000 || (unsigned)(p->low >> 32) != 0)
{
Byte temp = p->cache;
do
@@ -542,7 +584,7 @@ static void RangeEnc_FlushData(CRangeEnc *p)
RangeEnc_ShiftLow(p);
}
-static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits)
+static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, unsigned numBits)
{
do
{
@@ -605,7 +647,7 @@ static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol,
while (symbol < 0x10000);
}
-void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
+static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
{
UInt32 i;
for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
@@ -641,7 +683,7 @@ void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
-static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
+static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, const UInt32 *ProbPrices)
{
UInt32 price = 0;
symbol |= 0x100;
@@ -654,7 +696,7 @@ static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *Pro
return price;
}
-static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
+static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, const UInt32 *ProbPrices)
{
UInt32 price = 0;
UInt32 offs = 0x100;
@@ -698,7 +740,7 @@ static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLeve
}
}
-static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
+static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, const UInt32 *ProbPrices)
{
UInt32 price = 0;
symbol |= (1 << numBitLevels);
@@ -710,7 +752,7 @@ static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 s
return price;
}
-static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
+static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, const UInt32 *ProbPrices)
{
UInt32 price = 0;
UInt32 m = 1;
@@ -761,7 +803,7 @@ static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posSt
}
}
-static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
+static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, const UInt32 *ProbPrices)
{
UInt32 a0 = GET_PRICE_0a(p->choice);
UInt32 a1 = GET_PRICE_1a(p->choice);
@@ -784,20 +826,20 @@ static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UIn
prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
}
-static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
+static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, const UInt32 *ProbPrices)
{
LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
p->counters[posState] = p->tableSize;
}
-static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
+static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, const UInt32 *ProbPrices)
{
UInt32 posState;
for (posState = 0; posState < numPosStates; posState++)
LenPriceEnc_UpdateTable(p, posState, ProbPrices);
}
-static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
+static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, const UInt32 *ProbPrices)
{
LenEnc_Encode(&p->p, rc, symbol, posState);
if (updatePrice)
@@ -811,9 +853,10 @@ static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32
static void MovePos(CLzmaEnc *p, UInt32 num)
{
#ifdef SHOW_STAT
- ttt += num;
- printf("\n MovePos %d", num);
+ g_STAT_OFFSET += num;
+ printf("\n MovePos %u", num);
#endif
+
if (num != 0)
{
p->additionalOffset += num;
@@ -826,28 +869,32 @@ static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
UInt32 lenRes = 0, numPairs;
p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
+
#ifdef SHOW_STAT
- printf("\n i = %d numPairs = %d ", ttt, numPairs / 2);
- ttt++;
+ printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2);
+ g_STAT_OFFSET++;
{
UInt32 i;
for (i = 0; i < numPairs; i += 2)
- printf("%2d %6d | ", p->matches[i], p->matches[i + 1]);
+ printf("%2u %6u | ", p->matches[i], p->matches[i + 1]);
}
#endif
+
if (numPairs > 0)
{
lenRes = p->matches[numPairs - 2];
if (lenRes == p->numFastBytes)
{
- const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
- UInt32 distance = p->matches[numPairs - 1] + 1;
UInt32 numAvail = p->numAvail;
if (numAvail > LZMA_MATCH_LEN_MAX)
numAvail = LZMA_MATCH_LEN_MAX;
{
- const Byte *pby2 = pby - distance;
- for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
+ const Byte *pbyCur = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ const Byte *pby = pbyCur + lenRes;
+ ptrdiff_t dif = (ptrdiff_t)-1 - p->matches[numPairs - 1];
+ const Byte *pbyLim = pbyCur + numAvail;
+ for (; pby != pbyLim && *pby == pby[dif]; pby++);
+ lenRes = (UInt32)(pby - pbyCur);
}
}
}
@@ -932,7 +979,7 @@ static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
return p->optimumCurrentIndex;
}
-#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
+#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * (UInt32)0x300)
static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
{
@@ -976,7 +1023,7 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
UInt32 lenTest;
const Byte *data2;
reps[i] = p->reps[i];
- data2 = data - (reps[i] + 1);
+ data2 = data - reps[i] - 1;
if (data[0] != data2[0] || data[1] != data2[1])
{
repLens[i] = 0;
@@ -1120,12 +1167,12 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
cur = 0;
#ifdef SHOW_STAT2
- if (position >= 0)
+ /* if (position >= 0) */
{
unsigned i;
printf("\n pos = %4X", position);
for (i = cur; i <= lenEnd; i++)
- printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
+ printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price);
}
#endif
@@ -1277,7 +1324,7 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
/* try Literal + rep0 */
UInt32 temp;
UInt32 lenTest2;
- const Byte *data2 = data - (reps[0] + 1);
+ const Byte *data2 = data - reps[0] - 1;
UInt32 limit = p->numFastBytes + 1;
if (limit > numAvailFull)
limit = numAvailFull;
@@ -1320,7 +1367,7 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
UInt32 lenTest;
UInt32 lenTestTemp;
UInt32 price;
- const Byte *data2 = data - (reps[repIndex] + 1);
+ const Byte *data2 = data - reps[repIndex] - 1;
if (data[0] != data2[0] || data[1] != data2[1])
continue;
for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
@@ -1350,13 +1397,13 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
{
UInt32 lenTest2 = lenTest + 1;
UInt32 limit = lenTest2 + p->numFastBytes;
- UInt32 nextRepMatchPrice;
if (limit > numAvailFull)
limit = numAvailFull;
for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
lenTest2 -= lenTest + 1;
if (lenTest2 >= 2)
{
+ UInt32 nextRepMatchPrice;
UInt32 state2 = kRepNextStates[state];
UInt32 posStateNext = (position + lenTest) & p->pbMask;
UInt32 curAndLenCharPrice =
@@ -1437,16 +1484,16 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
if (/*_maxMode && */lenTest == matches[offs])
{
/* Try Match + Literal + Rep0 */
- const Byte *data2 = data - (curBack + 1);
+ const Byte *data2 = data - curBack - 1;
UInt32 lenTest2 = lenTest + 1;
UInt32 limit = lenTest2 + p->numFastBytes;
- UInt32 nextRepMatchPrice;
if (limit > numAvailFull)
limit = numAvailFull;
for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
lenTest2 -= lenTest + 1;
if (lenTest2 >= 2)
{
+ UInt32 nextRepMatchPrice;
UInt32 state2 = kMatchNextStates[state];
UInt32 posStateNext = (position + lenTest) & p->pbMask;
UInt32 curAndLenCharPrice = curAndLenPrice +
@@ -1520,7 +1567,7 @@ static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
for (i = 0; i < LZMA_NUM_REPS; i++)
{
UInt32 len;
- const Byte *data2 = data - (p->reps[i] + 1);
+ const Byte *data2 = data - p->reps[i] - 1;
if (data[0] != data2[0] || data[1] != data2[1])
continue;
for (len = 2; len < numAvail && data[len] == data2[len]; len++);
@@ -1589,7 +1636,7 @@ static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
for (i = 0; i < LZMA_NUM_REPS; i++)
{
UInt32 len, limit;
- const Byte *data2 = data - (p->reps[i] + 1);
+ const Byte *data2 = data - p->reps[i] - 1;
if (data[0] != data2[0] || data[1] != data2[1])
continue;
limit = mainLen - 1;
@@ -1685,6 +1732,7 @@ void LzmaEnc_Construct(CLzmaEnc *p)
{
RangeEnc_Construct(&p->rc);
MatchFinder_Construct(&p->matchFinderBase);
+
#ifndef _7ZIP_ST
MatchFinderMt_Construct(&p->matchFinderMt);
p->matchFinderMt.MatchFinder = &p->matchFinderBase;
@@ -1701,15 +1749,15 @@ void LzmaEnc_Construct(CLzmaEnc *p)
#endif
LzmaEnc_InitPriceTables(p->ProbPrices);
- p->litProbs = 0;
- p->saveState.litProbs = 0;
+ p->litProbs = NULL;
+ p->saveState.litProbs = NULL;
}
CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
{
void *p;
p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
- if (p != 0)
+ if (p)
LzmaEnc_Construct((CLzmaEnc *)p);
return p;
}
@@ -1718,8 +1766,8 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
{
alloc->Free(alloc, p->litProbs);
alloc->Free(alloc, p->saveState.litProbs);
- p->litProbs = 0;
- p->saveState.litProbs = 0;
+ p->litProbs = NULL;
+ p->saveState.litProbs = NULL;
}
void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
@@ -1727,6 +1775,7 @@ void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
#ifndef _7ZIP_ST
MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
#endif
+
MatchFinder_Free(&p->matchFinderBase, allocBig);
LzmaEnc_FreeLits(p, alloc);
RangeEnc_Free(&p->rc, alloc);
@@ -1763,7 +1812,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize
ReadMatchDistances(p, &numPairs);
RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
p->state = kLiteralNextStates[p->state];
- curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
+ curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset);
LitEnc_Encode(&p->rc, p->litProbs, curByte);
p->additionalOffset--;
nowPos32++;
@@ -1780,7 +1829,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize
len = GetOptimum(p, nowPos32, &pos);
#ifdef SHOW_STAT2
- printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos);
+ printf("\n pos = %4X, len = %u pos = %u", nowPos32, len, pos);
#endif
posState = nowPos32 & p->pbMask;
@@ -1889,7 +1938,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize
RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
break;
}
- else if (processed >= (1 << 15))
+ else if (processed >= (1 << 17))
{
p->nowPos64 += nowPos32 - startPos32;
return CheckErrors(p);
@@ -1905,22 +1954,21 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize
static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
{
UInt32 beforeSize = kNumOpts;
- Bool btMode;
if (!RangeEnc_Alloc(&p->rc, alloc))
return SZ_ERROR_MEM;
- btMode = (p->matchFinderBase.btMode != 0);
+
#ifndef _7ZIP_ST
- p->mtMode = (p->multiThread && !p->fastMode && btMode);
+ p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0));
#endif
{
unsigned lclp = p->lc + p->lp;
- if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
+ if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp)
{
LzmaEnc_FreeLits(p, alloc);
- p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
- p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
- if (p->litProbs == 0 || p->saveState.litProbs == 0)
+ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
+ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
+ if (!p->litProbs || !p->saveState.litProbs)
{
LzmaEnc_FreeLits(p, alloc);
return SZ_ERROR_MEM;
@@ -1929,7 +1977,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, I
}
}
- p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
+ p->matchFinderBase.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0);
if (beforeSize + p->dictSize < keepWindowSize)
beforeSize = keepWindowSize - p->dictSize;
@@ -1949,6 +1997,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, I
p->matchFinderObj = &p->matchFinderBase;
MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
}
+
return SZ_OK;
}
@@ -1977,9 +2026,10 @@ void LzmaEnc_Init(CLzmaEnc *p)
}
{
- UInt32 num = 0x300 << (p->lp + p->lc);
+ UInt32 num = (UInt32)0x300 << (p->lp + p->lc);
+ CLzmaProb *probs = p->litProbs;
for (i = 0; i < num; i++)
- p->litProbs[i] = kProbInitValue;
+ probs[i] = kProbInitValue;
}
{
@@ -2086,10 +2136,11 @@ void LzmaEnc_Finish(CLzmaEncHandle pp)
if (p->mtMode)
MatchFinderMt_ReleaseStream(&p->matchFinderMt);
#else
- (void)pp;
+ UNUSED_VAR(pp);
#endif
}
+
typedef struct
{
ISeqOutStream funcTable;
@@ -2119,12 +2170,14 @@ UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
}
+
const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
{
const CLzmaEnc *p = (CLzmaEnc *)pp;
return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
}
+
SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
{
@@ -2159,23 +2212,23 @@ SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
return res;
}
+
static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
{
SRes res = SZ_OK;
#ifndef _7ZIP_ST
Byte allocaDummy[0x300];
- int i = 0;
- for (i = 0; i < 16; i++)
- allocaDummy[i] = (Byte)i;
+ allocaDummy[0] = 0;
+ allocaDummy[1] = allocaDummy[0];
#endif
for (;;)
{
res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
- if (res != SZ_OK || p->finished != 0)
+ if (res != SZ_OK || p->finished)
break;
- if (progress != 0)
+ if (progress)
{
res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
if (res != SZ_OK)
@@ -2185,10 +2238,19 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
}
}
}
+
LzmaEnc_Finish(p);
+
+ /*
+ if (res == S_OK && !Inline_MatchFinder_IsFinishedOK(&p->matchFinderBase))
+ res = SZ_ERROR_FAIL;
+ }
+ */
+
return res;
}
+
SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
ISzAlloc *alloc, ISzAlloc *allocBig)
{
@@ -2196,28 +2258,27 @@ SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *i
return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
}
+
SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
{
CLzmaEnc *p = (CLzmaEnc *)pp;
- int i;
+ unsigned i;
UInt32 dictSize = p->dictSize;
if (*size < LZMA_PROPS_SIZE)
return SZ_ERROR_PARAM;
*size = LZMA_PROPS_SIZE;
props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
- for (i = 11; i <= 30; i++)
+ if (dictSize >= ((UInt32)1 << 22))
{
- if (dictSize <= ((UInt32)2 << i))
- {
- dictSize = (2 << i);
- break;
- }
- if (dictSize <= ((UInt32)3 << i))
- {
- dictSize = (3 << i);
- break;
- }
+ UInt32 kDictMask = ((UInt32)1 << 20) - 1;
+ if (dictSize < (UInt32)0xFFFFFFFF - kDictMask)
+ dictSize = (dictSize + kDictMask) & ~kDictMask;
+ }
+ else for (i = 11; i <= 30; i++)
+ {
+ if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; }
+ if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; }
}
for (i = 0; i < 4; i++)
@@ -2225,6 +2286,7 @@ SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
return SZ_OK;
}
+
SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
{
@@ -2233,19 +2295,22 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte
CSeqOutStreamBuf outStream;
- LzmaEnc_SetInputBuf(p, src, srcLen);
-
outStream.funcTable.Write = MyWrite;
outStream.data = dest;
outStream.rem = *destLen;
outStream.overflow = False;
p->writeEndMark = writeEndMark;
-
p->rc.outStream = &outStream.funcTable;
+
res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
+
if (res == SZ_OK)
+ {
res = LzmaEnc_Encode2(p, progress);
+ if (res == SZ_OK && p->nowPos64 != srcLen)
+ res = SZ_ERROR_FAIL;
+ }
*destLen -= outStream.rem;
if (outStream.overflow)
@@ -2253,13 +2318,14 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte
return res;
}
+
SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
{
CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
SRes res;
- if (p == 0)
+ if (!p)
return SZ_ERROR_MEM;
res = LzmaEnc_SetProps(p, props);
diff --git a/lzma/C/LzmaEnc.h b/lzma/C/LzmaEnc.h
index 7573ba01bf..c2806b45f4 100644
--- a/lzma/C/LzmaEnc.h
+++ b/lzma/C/LzmaEnc.h
@@ -1,10 +1,10 @@
/* LzmaEnc.h -- LZMA Encoder
-2011-01-27 : Igor Pavlov : Public domain */
+2013-01-18 : Igor Pavlov : Public domain */
#ifndef __LZMA_ENC_H
#define __LZMA_ENC_H
-#include "Types.h"
+#include "7zTypes.h"
EXTERN_C_BEGIN
@@ -16,7 +16,7 @@ typedef struct _CLzmaEncProps
UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
(1 << 12) <= dictSize <= (1 << 30) for 64-bit version
default = (1 << 24) */
- UInt32 reduceSize; /* estimated size of data that will be compressed. default = 0xFFFFFFFF.
+ UInt64 reduceSize; /* estimated size of data that will be compressed. default = 0xFFFFFFFF.
Encoder uses this value to reduce dictionary size */
int lc; /* 0 <= lc <= 8, default = 3 */
int lp; /* 0 <= lp <= 4, default = 0 */
diff --git a/lzma/C/Ppmd.h b/lzma/C/Ppmd.h
new file mode 100644
index 0000000000..25ce2d28fb
--- /dev/null
+++ b/lzma/C/Ppmd.h
@@ -0,0 +1,85 @@
+/* Ppmd.h -- PPMD codec common code
+2013-01-18 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#ifndef __PPMD_H
+#define __PPMD_H
+
+#include "CpuArch.h"
+
+EXTERN_C_BEGIN
+
+#ifdef MY_CPU_32BIT
+ #define PPMD_32BIT
+#endif
+
+#define PPMD_INT_BITS 7
+#define PPMD_PERIOD_BITS 7
+#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))
+
+#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))
+#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)
+#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))
+#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))
+
+#define PPMD_N1 4
+#define PPMD_N2 4
+#define PPMD_N3 4
+#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)
+#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)
+
+#pragma pack(push, 1)
+/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */
+
+/* SEE-contexts for PPM-contexts with masked symbols */
+typedef struct
+{
+ UInt16 Summ; /* Freq */
+ Byte Shift; /* Speed of Freq change; low Shift is for fast change */
+ Byte Count; /* Count to next change of Shift */
+} CPpmd_See;
+
+#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \
+ { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); }
+
+typedef struct
+{
+ Byte Symbol;
+ Byte Freq;
+ UInt16 SuccessorLow;
+ UInt16 SuccessorHigh;
+} CPpmd_State;
+
+#pragma pack(pop)
+
+typedef
+ #ifdef PPMD_32BIT
+ CPpmd_State *
+ #else
+ UInt32
+ #endif
+ CPpmd_State_Ref;
+
+typedef
+ #ifdef PPMD_32BIT
+ void *
+ #else
+ UInt32
+ #endif
+ CPpmd_Void_Ref;
+
+typedef
+ #ifdef PPMD_32BIT
+ Byte *
+ #else
+ UInt32
+ #endif
+ CPpmd_Byte_Ref;
+
+#define PPMD_SetAllBitsIn256Bytes(p) \
+ { unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \
+ p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }}
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/Ppmd7.c b/lzma/C/Ppmd7.c
new file mode 100644
index 0000000000..735651f5d8
--- /dev/null
+++ b/lzma/C/Ppmd7.c
@@ -0,0 +1,710 @@
+/* Ppmd7.c -- PPMdH codec
+2015-09-28 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "Precomp.h"
+
+#include
+
+#include "Ppmd7.h"
+
+const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
+
+#define MAX_FREQ 124
+#define UNIT_SIZE 12
+
+#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
+#define U2I(nu) (p->Units2Indx[(nu) - 1])
+#define I2U(indx) (p->Indx2Units[indx])
+
+#ifdef PPMD_32BIT
+ #define REF(ptr) (ptr)
+#else
+ #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
+#endif
+
+#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
+
+#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
+#define STATS(ctx) Ppmd7_GetStats(p, ctx)
+#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx)
+#define SUFFIX(ctx) CTX((ctx)->Suffix)
+
+typedef CPpmd7_Context * CTX_PTR;
+
+struct CPpmd7_Node_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd7_Node_ *
+ #else
+ UInt32
+ #endif
+ CPpmd7_Node_Ref;
+
+typedef struct CPpmd7_Node_
+{
+ UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */
+ UInt16 NU;
+ CPpmd7_Node_Ref Next; /* must be at offset >= 4 */
+ CPpmd7_Node_Ref Prev;
+} CPpmd7_Node;
+
+#ifdef PPMD_32BIT
+ #define NODE(ptr) (ptr)
+#else
+ #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs)))
+#endif
+
+void Ppmd7_Construct(CPpmd7 *p)
+{
+ unsigned i, k, m;
+
+ p->Base = 0;
+
+ for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
+ do { p->Units2Indx[k++] = (Byte)i; } while (--step);
+ p->Indx2Units[i] = (Byte)k;
+ }
+
+ p->NS2BSIndx[0] = (0 << 1);
+ p->NS2BSIndx[1] = (1 << 1);
+ memset(p->NS2BSIndx + 2, (2 << 1), 9);
+ memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
+
+ for (i = 0; i < 3; i++)
+ p->NS2Indx[i] = (Byte)i;
+ for (m = i, k = 1; i < 256; i++)
+ {
+ p->NS2Indx[i] = (Byte)m;
+ if (--k == 0)
+ k = (++m) - 2;
+ }
+
+ memset(p->HB2Flag, 0, 0x40);
+ memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40);
+}
+
+void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->Base);
+ p->Size = 0;
+ p->Base = 0;
+}
+
+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
+{
+ if (p->Base == 0 || p->Size != size)
+ {
+ Ppmd7_Free(p, alloc);
+ p->AlignOffset =
+ #ifdef PPMD_32BIT
+ (4 - size) & 3;
+ #else
+ 4 - (size & 3);
+ #endif
+ if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size
+ #ifndef PPMD_32BIT
+ + UNIT_SIZE
+ #endif
+ )) == 0)
+ return False;
+ p->Size = size;
+ }
+ return True;
+}
+
+static void InsertNode(CPpmd7 *p, void *node, unsigned indx)
+{
+ *((CPpmd_Void_Ref *)node) = p->FreeList[indx];
+ p->FreeList[indx] = REF(node);
+}
+
+static void *RemoveNode(CPpmd7 *p, unsigned indx)
+{
+ CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]);
+ p->FreeList[indx] = *node;
+ return node;
+}
+
+static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
+{
+ unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
+ ptr = (Byte *)ptr + U2B(I2U(newIndx));
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
+ }
+ InsertNode(p, ptr, i);
+}
+
+static void GlueFreeBlocks(CPpmd7 *p)
+{
+ #ifdef PPMD_32BIT
+ CPpmd7_Node headItem;
+ CPpmd7_Node_Ref head = &headItem;
+ #else
+ CPpmd7_Node_Ref head = p->AlignOffset + p->Size;
+ #endif
+
+ CPpmd7_Node_Ref n = head;
+ unsigned i;
+
+ p->GlueCount = 255;
+
+ /* create doubly-linked list of free blocks */
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ UInt16 nu = I2U(i);
+ CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i];
+ p->FreeList[i] = 0;
+ while (next != 0)
+ {
+ CPpmd7_Node *node = NODE(next);
+ node->Next = n;
+ n = NODE(n)->Prev = next;
+ next = *(const CPpmd7_Node_Ref *)node;
+ node->Stamp = 0;
+ node->NU = (UInt16)nu;
+ }
+ }
+ NODE(head)->Stamp = 1;
+ NODE(head)->Next = n;
+ NODE(n)->Prev = head;
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd7_Node *)p->LoUnit)->Stamp = 1;
+
+ /* Glue free blocks */
+ while (n != head)
+ {
+ CPpmd7_Node *node = NODE(n);
+ UInt32 nu = (UInt32)node->NU;
+ for (;;)
+ {
+ CPpmd7_Node *node2 = NODE(n) + nu;
+ nu += node2->NU;
+ if (node2->Stamp != 0 || nu >= 0x10000)
+ break;
+ NODE(node2->Prev)->Next = node2->Next;
+ NODE(node2->Next)->Prev = node2->Prev;
+ node->NU = (UInt16)nu;
+ }
+ n = node->Next;
+ }
+
+ /* Fill lists of free blocks */
+ for (n = NODE(head)->Next; n != head;)
+ {
+ CPpmd7_Node *node = NODE(n);
+ unsigned nu;
+ CPpmd7_Node_Ref next = node->Next;
+ for (nu = node->NU; nu > 128; nu -= 128, node += 128)
+ InsertNode(p, node, PPMD_NUM_INDEXES - 1);
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, node + k, nu - k - 1);
+ }
+ InsertNode(p, node, i);
+ n = next;
+ }
+}
+
+static void *AllocUnitsRare(CPpmd7 *p, unsigned indx)
+{
+ unsigned i;
+ void *retVal;
+ if (p->GlueCount == 0)
+ {
+ GlueFreeBlocks(p);
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ }
+ i = indx;
+ do
+ {
+ if (++i == PPMD_NUM_INDEXES)
+ {
+ UInt32 numBytes = U2B(I2U(indx));
+ p->GlueCount--;
+ return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);
+ }
+ }
+ while (p->FreeList[i] == 0);
+ retVal = RemoveNode(p, i);
+ SplitBlock(p, retVal, i, indx);
+ return retVal;
+}
+
+static void *AllocUnits(CPpmd7 *p, unsigned indx)
+{
+ UInt32 numBytes;
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ numBytes = U2B(I2U(indx));
+ if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))
+ {
+ void *retVal = p->LoUnit;
+ p->LoUnit += numBytes;
+ return retVal;
+ }
+ return AllocUnitsRare(p, indx);
+}
+
+#define MyMem12Cpy(dest, src, num) \
+ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \
+ do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while (--n); }
+
+static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
+{
+ unsigned i0 = U2I(oldNU);
+ unsigned i1 = U2I(newNU);
+ if (i0 == i1)
+ return oldPtr;
+ if (p->FreeList[i1] != 0)
+ {
+ void *ptr = RemoveNode(p, i1);
+ MyMem12Cpy(ptr, oldPtr, newNU);
+ InsertNode(p, oldPtr, i0);
+ return ptr;
+ }
+ SplitBlock(p, oldPtr, i0, i1);
+ return oldPtr;
+}
+
+#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))
+
+static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
+{
+ (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);
+ (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
+}
+
+static void RestartModel(CPpmd7 *p)
+{
+ unsigned i, k, m;
+
+ memset(p->FreeList, 0, sizeof(p->FreeList));
+ p->Text = p->Base + p->AlignOffset;
+ p->HiUnit = p->Text + p->Size;
+ p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
+ p->GlueCount = 0;
+
+ p->OrderFall = p->MaxOrder;
+ p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
+ p->PrevSuccess = 0;
+
+ p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
+ p->MinContext->Suffix = 0;
+ p->MinContext->NumStats = 256;
+ p->MinContext->SummFreq = 256 + 1;
+ p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */
+ p->LoUnit += U2B(256 / 2);
+ p->MinContext->Stats = REF(p->FoundState);
+ for (i = 0; i < 256; i++)
+ {
+ CPpmd_State *s = &p->FoundState[i];
+ s->Symbol = (Byte)i;
+ s->Freq = 1;
+ SetSuccessor(s, 0);
+ }
+
+ for (i = 0; i < 128; i++)
+ for (k = 0; k < 8; k++)
+ {
+ UInt16 *dest = p->BinSumm[i] + k;
+ UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2));
+ for (m = 0; m < 64; m += 8)
+ dest[m] = val;
+ }
+
+ for (i = 0; i < 25; i++)
+ for (k = 0; k < 16; k++)
+ {
+ CPpmd_See *s = &p->See[i][k];
+ s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4));
+ s->Count = 4;
+ }
+}
+
+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder)
+{
+ p->MaxOrder = maxOrder;
+ RestartModel(p);
+ p->DummySee.Shift = PPMD_PERIOD_BITS;
+ p->DummySee.Summ = 0; /* unused */
+ p->DummySee.Count = 64; /* unused */
+}
+
+static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip)
+{
+ CPpmd_State upState;
+ CTX_PTR c = p->MinContext;
+ CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
+ CPpmd_State *ps[PPMD7_MAX_ORDER];
+ unsigned numPs = 0;
+
+ if (!skip)
+ ps[numPs++] = p->FoundState;
+
+ while (c->Suffix)
+ {
+ CPpmd_Void_Ref successor;
+ CPpmd_State *s;
+ c = SUFFIX(c);
+ if (c->NumStats != 1)
+ {
+ for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);
+ }
+ else
+ s = ONE_STATE(c);
+ successor = SUCCESSOR(s);
+ if (successor != upBranch)
+ {
+ c = CTX(successor);
+ if (numPs == 0)
+ return c;
+ break;
+ }
+ ps[numPs++] = s;
+ }
+
+ upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch);
+ SetSuccessor(&upState, upBranch + 1);
+
+ if (c->NumStats == 1)
+ upState.Freq = ONE_STATE(c)->Freq;
+ else
+ {
+ UInt32 cf, s0;
+ CPpmd_State *s;
+ for (s = STATS(c); s->Symbol != upState.Symbol; s++);
+ cf = s->Freq - 1;
+ s0 = c->SummFreq - c->NumStats - cf;
+ upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));
+ }
+
+ do
+ {
+ /* Create Child */
+ CTX_PTR c1; /* = AllocContext(p); */
+ if (p->HiUnit != p->LoUnit)
+ c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);
+ else if (p->FreeList[0] != 0)
+ c1 = (CTX_PTR)RemoveNode(p, 0);
+ else
+ {
+ c1 = (CTX_PTR)AllocUnitsRare(p, 0);
+ if (!c1)
+ return NULL;
+ }
+ c1->NumStats = 1;
+ *ONE_STATE(c1) = upState;
+ c1->Suffix = REF(c);
+ SetSuccessor(ps[--numPs], REF(c1));
+ c = c1;
+ }
+ while (numPs != 0);
+
+ return c;
+}
+
+static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
+{
+ CPpmd_State tmp = *t1;
+ *t1 = *t2;
+ *t2 = tmp;
+}
+
+static void UpdateModel(CPpmd7 *p)
+{
+ CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);
+ CTX_PTR c;
+ unsigned s0, ns;
+
+ if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
+ {
+ c = SUFFIX(p->MinContext);
+
+ if (c->NumStats == 1)
+ {
+ CPpmd_State *s = ONE_STATE(c);
+ if (s->Freq < 32)
+ s->Freq++;
+ }
+ else
+ {
+ CPpmd_State *s = STATS(c);
+ if (s->Symbol != p->FoundState->Symbol)
+ {
+ do { s++; } while (s->Symbol != p->FoundState->Symbol);
+ if (s[0].Freq >= s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ s--;
+ }
+ }
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq += 2;
+ c->SummFreq += 2;
+ }
+ }
+ }
+
+ if (p->OrderFall == 0)
+ {
+ p->MinContext = p->MaxContext = CreateSuccessors(p, True);
+ if (p->MinContext == 0)
+ {
+ RestartModel(p);
+ return;
+ }
+ SetSuccessor(p->FoundState, REF(p->MinContext));
+ return;
+ }
+
+ *p->Text++ = p->FoundState->Symbol;
+ successor = REF(p->Text);
+ if (p->Text >= p->UnitsStart)
+ {
+ RestartModel(p);
+ return;
+ }
+
+ if (fSuccessor)
+ {
+ if (fSuccessor <= successor)
+ {
+ CTX_PTR cs = CreateSuccessors(p, False);
+ if (cs == NULL)
+ {
+ RestartModel(p);
+ return;
+ }
+ fSuccessor = REF(cs);
+ }
+ if (--p->OrderFall == 0)
+ {
+ successor = fSuccessor;
+ p->Text -= (p->MaxContext != p->MinContext);
+ }
+ }
+ else
+ {
+ SetSuccessor(p->FoundState, successor);
+ fSuccessor = REF(p->MinContext);
+ }
+
+ s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1);
+
+ for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c))
+ {
+ unsigned ns1;
+ UInt32 cf, sf;
+ if ((ns1 = c->NumStats) != 1)
+ {
+ if ((ns1 & 1) == 0)
+ {
+ /* Expand for one UNIT */
+ unsigned oldNU = ns1 >> 1;
+ unsigned i = U2I(oldNU);
+ if (i != U2I(oldNU + 1))
+ {
+ void *ptr = AllocUnits(p, i + 1);
+ void *oldPtr;
+ if (!ptr)
+ {
+ RestartModel(p);
+ return;
+ }
+ oldPtr = STATS(c);
+ MyMem12Cpy(ptr, oldPtr, oldNU);
+ InsertNode(p, oldPtr, i);
+ c->Stats = STATS_REF(ptr);
+ }
+ }
+ c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1)));
+ }
+ else
+ {
+ CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);
+ if (!s)
+ {
+ RestartModel(p);
+ return;
+ }
+ *s = *ONE_STATE(c);
+ c->Stats = REF(s);
+ if (s->Freq < MAX_FREQ / 4 - 1)
+ s->Freq <<= 1;
+ else
+ s->Freq = MAX_FREQ - 4;
+ c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3));
+ }
+ cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6);
+ sf = (UInt32)s0 + c->SummFreq;
+ if (cf < 6 * sf)
+ {
+ cf = 1 + (cf > sf) + (cf >= 4 * sf);
+ c->SummFreq += 3;
+ }
+ else
+ {
+ cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);
+ c->SummFreq = (UInt16)(c->SummFreq + cf);
+ }
+ {
+ CPpmd_State *s = STATS(c) + ns1;
+ SetSuccessor(s, successor);
+ s->Symbol = p->FoundState->Symbol;
+ s->Freq = (Byte)cf;
+ c->NumStats = (UInt16)(ns1 + 1);
+ }
+ }
+ p->MaxContext = p->MinContext = CTX(fSuccessor);
+}
+
+static void Rescale(CPpmd7 *p)
+{
+ unsigned i, adder, sumFreq, escFreq;
+ CPpmd_State *stats = STATS(p->MinContext);
+ CPpmd_State *s = p->FoundState;
+ {
+ CPpmd_State tmp = *s;
+ for (; s != stats; s--)
+ s[0] = s[-1];
+ *s = tmp;
+ }
+ escFreq = p->MinContext->SummFreq - s->Freq;
+ s->Freq += 4;
+ adder = (p->OrderFall != 0);
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq = s->Freq;
+
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ escFreq -= (++s)->Freq;
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq += s->Freq;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ CPpmd_State *s1 = s;
+ CPpmd_State tmp = *s1;
+ do
+ s1[0] = s1[-1];
+ while (--s1 != stats && tmp.Freq > s1[-1].Freq);
+ *s1 = tmp;
+ }
+ }
+ while (--i);
+
+ if (s->Freq == 0)
+ {
+ unsigned numStats = p->MinContext->NumStats;
+ unsigned n0, n1;
+ do { i++; } while ((--s)->Freq == 0);
+ escFreq += i;
+ p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i);
+ if (p->MinContext->NumStats == 1)
+ {
+ CPpmd_State tmp = *stats;
+ do
+ {
+ tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1));
+ escFreq >>= 1;
+ }
+ while (escFreq > 1);
+ InsertNode(p, stats, U2I(((numStats + 1) >> 1)));
+ *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;
+ return;
+ }
+ n0 = (numStats + 1) >> 1;
+ n1 = (p->MinContext->NumStats + 1) >> 1;
+ if (n0 != n1)
+ p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
+ }
+ p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
+ p->FoundState = STATS(p->MinContext);
+}
+
+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq)
+{
+ CPpmd_See *see;
+ unsigned nonMasked = p->MinContext->NumStats - numMasked;
+ if (p->MinContext->NumStats != 256)
+ {
+ see = p->See[p->NS2Indx[nonMasked - 1]] +
+ (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +
+ 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +
+ 4 * (numMasked > nonMasked) +
+ p->HiBitsFlag;
+ {
+ unsigned r = (see->Summ >> see->Shift);
+ see->Summ = (UInt16)(see->Summ - r);
+ *escFreq = r + (r == 0);
+ }
+ }
+ else
+ {
+ see = &p->DummySee;
+ *escFreq = 1;
+ }
+ return see;
+}
+
+static void NextContext(CPpmd7 *p)
+{
+ CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
+ if (p->OrderFall == 0 && (Byte *)c > p->Text)
+ p->MinContext = p->MaxContext = c;
+ else
+ UpdateModel(p);
+}
+
+void Ppmd7_Update1(CPpmd7 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ s->Freq += 4;
+ p->MinContext->SummFreq += 4;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ p->FoundState = --s;
+ if (s->Freq > MAX_FREQ)
+ Rescale(p);
+ }
+ NextContext(p);
+}
+
+void Ppmd7_Update1_0(CPpmd7 *p)
+{
+ p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq);
+ p->RunLength += p->PrevSuccess;
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ NextContext(p);
+}
+
+void Ppmd7_UpdateBin(CPpmd7 *p)
+{
+ p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0));
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ NextContext(p);
+}
+
+void Ppmd7_Update2(CPpmd7 *p)
+{
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ p->RunLength = p->InitRL;
+ UpdateModel(p);
+}
diff --git a/lzma/C/Ppmd7.h b/lzma/C/Ppmd7.h
new file mode 100644
index 0000000000..56e81eb123
--- /dev/null
+++ b/lzma/C/Ppmd7.h
@@ -0,0 +1,140 @@
+/* Ppmd7.h -- PPMdH compression codec
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+/* This code supports virtual RangeDecoder and includes the implementation
+of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H.
+If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */
+
+#ifndef __PPMD7_H
+#define __PPMD7_H
+
+#include "Ppmd.h"
+
+EXTERN_C_BEGIN
+
+#define PPMD7_MIN_ORDER 2
+#define PPMD7_MAX_ORDER 64
+
+#define PPMD7_MIN_MEM_SIZE (1 << 11)
+#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
+
+struct CPpmd7_Context_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd7_Context_ *
+ #else
+ UInt32
+ #endif
+ CPpmd7_Context_Ref;
+
+typedef struct CPpmd7_Context_
+{
+ UInt16 NumStats;
+ UInt16 SummFreq;
+ CPpmd_State_Ref Stats;
+ CPpmd7_Context_Ref Suffix;
+} CPpmd7_Context;
+
+#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
+
+typedef struct
+{
+ CPpmd7_Context *MinContext, *MaxContext;
+ CPpmd_State *FoundState;
+ unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag;
+ Int32 RunLength, InitRL; /* must be 32-bit at least */
+
+ UInt32 Size;
+ UInt32 GlueCount;
+ Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
+ UInt32 AlignOffset;
+
+ Byte Indx2Units[PPMD_NUM_INDEXES];
+ Byte Units2Indx[128];
+ CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
+ Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
+ CPpmd_See DummySee, See[25][16];
+ UInt16 BinSumm[128][64];
+} CPpmd7;
+
+void Ppmd7_Construct(CPpmd7 *p);
+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc);
+void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc);
+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder);
+#define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
+
+
+/* ---------- Internal Functions ---------- */
+
+extern const Byte PPMD7_kExpEscape[16];
+
+#ifdef PPMD_32BIT
+ #define Ppmd7_GetPtr(p, ptr) (ptr)
+ #define Ppmd7_GetContext(p, ptr) (ptr)
+ #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats)
+#else
+ #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
+ #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs)))
+ #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats)))
+#endif
+
+void Ppmd7_Update1(CPpmd7 *p);
+void Ppmd7_Update1_0(CPpmd7 *p);
+void Ppmd7_Update2(CPpmd7 *p);
+void Ppmd7_UpdateBin(CPpmd7 *p);
+
+#define Ppmd7_GetBinSumm(p) \
+ &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \
+ p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \
+ (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \
+ 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \
+ ((p->RunLength >> 26) & 0x20)]
+
+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);
+
+
+/* ---------- Decode ---------- */
+
+typedef struct
+{
+ UInt32 (*GetThreshold)(void *p, UInt32 total);
+ void (*Decode)(void *p, UInt32 start, UInt32 size);
+ UInt32 (*DecodeBit)(void *p, UInt32 size0);
+} IPpmd7_RangeDec;
+
+typedef struct
+{
+ IPpmd7_RangeDec p;
+ UInt32 Range;
+ UInt32 Code;
+ IByteIn *Stream;
+} CPpmd7z_RangeDec;
+
+void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p);
+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p);
+#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
+
+int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc);
+
+
+/* ---------- Encode ---------- */
+
+typedef struct
+{
+ UInt64 Low;
+ UInt32 Range;
+ Byte Cache;
+ UInt64 CacheSize;
+ IByteOut *Stream;
+} CPpmd7z_RangeEnc;
+
+void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p);
+void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p);
+
+void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/Ppmd7Dec.c b/lzma/C/Ppmd7Dec.c
new file mode 100644
index 0000000000..3d01d76440
--- /dev/null
+++ b/lzma/C/Ppmd7Dec.c
@@ -0,0 +1,189 @@
+/* Ppmd7Dec.c -- PPMdH Decoder
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "Precomp.h"
+
+#include "Ppmd7.h"
+
+#define kTopValue (1 << 24)
+
+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p)
+{
+ unsigned i;
+ p->Code = 0;
+ p->Range = 0xFFFFFFFF;
+ if (p->Stream->Read((void *)p->Stream) != 0)
+ return False;
+ for (i = 0; i < 4; i++)
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ return (p->Code < 0xFFFFFFFF);
+}
+
+static UInt32 Range_GetThreshold(void *pp, UInt32 total)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ return (p->Code) / (p->Range /= total);
+}
+
+static void Range_Normalize(CPpmd7z_RangeDec *p)
+{
+ if (p->Range < kTopValue)
+ {
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ p->Range <<= 8;
+ if (p->Range < kTopValue)
+ {
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ p->Range <<= 8;
+ }
+ }
+}
+
+static void Range_Decode(void *pp, UInt32 start, UInt32 size)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ p->Code -= start * p->Range;
+ p->Range *= size;
+ Range_Normalize(p);
+}
+
+static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ UInt32 newBound = (p->Range >> 14) * size0;
+ UInt32 symbol;
+ if (p->Code < newBound)
+ {
+ symbol = 0;
+ p->Range = newBound;
+ }
+ else
+ {
+ symbol = 1;
+ p->Code -= newBound;
+ p->Range -= newBound;
+ }
+ Range_Normalize(p);
+ return symbol;
+}
+
+void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)
+{
+ p->p.GetThreshold = Range_GetThreshold;
+ p->p.Decode = Range_Decode;
+ p->p.DecodeBit = Range_DecodeBit;
+}
+
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 1)
+ {
+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
+ unsigned i;
+ UInt32 count, hiCnt;
+ if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq))
+ {
+ Byte symbol;
+ rc->Decode(rc, 0, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update1_0(p);
+ return symbol;
+ }
+ p->PrevSuccess = 0;
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ if ((hiCnt += (++s)->Freq) > count)
+ {
+ Byte symbol;
+ rc->Decode(rc, hiCnt - s->Freq, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update1(p);
+ return symbol;
+ }
+ }
+ while (--i);
+ if (count >= p->MinContext->SummFreq)
+ return -2;
+ p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
+ rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt);
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats - 1;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd7_GetBinSumm(p);
+ if (rc->DecodeBit(rc, *prob) == 0)
+ {
+ Byte symbol;
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
+ Ppmd7_UpdateBin(p);
+ return symbol;
+ }
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ for (;;)
+ {
+ CPpmd_State *ps[256], *s;
+ UInt32 freqSum, count, hiCnt;
+ CPpmd_See *see;
+ unsigned i, num, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return -1;
+ p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+ hiCnt = 0;
+ s = Ppmd7_GetStats(p, p->MinContext);
+ i = 0;
+ num = p->MinContext->NumStats - numMasked;
+ do
+ {
+ int k = (int)(MASK(s->Symbol));
+ hiCnt += (s->Freq & k);
+ ps[i] = s++;
+ i -= k;
+ }
+ while (i != num);
+
+ see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
+ freqSum += hiCnt;
+ count = rc->GetThreshold(rc, freqSum);
+
+ if (count < hiCnt)
+ {
+ Byte symbol;
+ CPpmd_State **pps = ps;
+ for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);
+ s = *pps;
+ rc->Decode(rc, hiCnt - s->Freq, s->Freq);
+ Ppmd_See_Update(see);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update2(p);
+ return symbol;
+ }
+ if (count >= freqSum)
+ return -2;
+ rc->Decode(rc, hiCnt, freqSum - hiCnt);
+ see->Summ = (UInt16)(see->Summ + freqSum);
+ do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);
+ }
+}
diff --git a/lzma/C/Precomp.h b/lzma/C/Precomp.h
new file mode 100644
index 0000000000..edb5814439
--- /dev/null
+++ b/lzma/C/Precomp.h
@@ -0,0 +1,10 @@
+/* Precomp.h -- StdAfx
+2013-11-12 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_PRECOMP_H
+#define __7Z_PRECOMP_H
+
+#include "Compiler.h"
+/* #include "7zTypes.h" */
+
+#endif
diff --git a/lzma/C/Threads.c b/lzma/C/Threads.c
index 4be44fb0f8..ece07e618a 100644
--- a/lzma/C/Threads.c
+++ b/lzma/C/Threads.c
@@ -1,7 +1,9 @@
/* Threads.c -- multithreading library
-2009-09-20 : Igor Pavlov : Public domain */
+2014-09-21 : Igor Pavlov : Public domain */
-#ifndef _WIN32_WCE
+#include "Precomp.h"
+
+#ifndef UNDER_CE
#include
#endif
@@ -29,14 +31,21 @@ WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE)
WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
{
- unsigned threadId; /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
- *p =
- #ifdef UNDER_CE
- CreateThread(0, 0, func, param, 0, &threadId);
- #else
- (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId);
- #endif
- /* maybe we must use errno here, but probably GetLastError() is also OK. */
+ /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
+
+ #ifdef UNDER_CE
+
+ DWORD threadId;
+ *p = CreateThread(0, 0, func, param, 0, &threadId);
+
+ #else
+
+ unsigned threadId;
+ *p = (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId);
+
+ #endif
+
+ /* maybe we must use errno here, but probably GetLastError() is also OK. */
return HandleToWRes(*p);
}
diff --git a/lzma/C/Threads.h b/lzma/C/Threads.h
index 6a7afa8299..e927208d79 100644
--- a/lzma/C/Threads.h
+++ b/lzma/C/Threads.h
@@ -1,15 +1,17 @@
/* Threads.h -- multithreading library
-2009-03-27 : Igor Pavlov : Public domain */
+2013-11-12 : Igor Pavlov : Public domain */
#ifndef __7Z_THREADS_H
#define __7Z_THREADS_H
-#include "Types.h"
-
-#ifdef __cplusplus
-extern "C" {
+#ifdef _WIN32
+#include
#endif
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
WRes HandlePtr_Close(HANDLE *h);
WRes Handle_WaitObject(HANDLE h);
@@ -18,7 +20,15 @@ typedef HANDLE CThread;
#define Thread_WasCreated(p) (*(p) != NULL)
#define Thread_Close(p) HandlePtr_Close(p)
#define Thread_Wait(p) Handle_WaitObject(*(p))
-typedef unsigned THREAD_FUNC_RET_TYPE;
+
+typedef
+#ifdef UNDER_CE
+ DWORD
+#else
+ unsigned
+#endif
+ THREAD_FUNC_RET_TYPE;
+
#define THREAD_FUNC_CALL_TYPE MY_STD_CALL
#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *);
@@ -52,8 +62,6 @@ WRes CriticalSection_Init(CCriticalSection *p);
#define CriticalSection_Enter(p) EnterCriticalSection(p)
#define CriticalSection_Leave(p) LeaveCriticalSection(p)
-#ifdef __cplusplus
-}
-#endif
+EXTERN_C_END
#endif
diff --git a/lzma/CMakeLists.txt b/lzma/CMakeLists.txt
index 7cd330cc8a..9c9de9152e 100644
--- a/lzma/CMakeLists.txt
+++ b/lzma/CMakeLists.txt
@@ -6,21 +6,27 @@ if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fomit-frame-pointer" )
endif( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
+set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_7ZIP_PPMD_SUPPPORT" )
+
set( LZMA_FILES
+ C/7zArcIn.c
C/7zBuf.c
C/7zCrc.c
C/7zCrcOpt.c
C/7zDec.c
- C/7zIn.c
C/7zStream.c
C/Bcj2.c
C/Bra.c
C/Bra86.c
+ C/BraIA64.c
C/CpuArch.c
+ C/Delta.c
C/LzFind.c
C/Lzma2Dec.c
C/LzmaDec.c
- C/LzmaEnc.c )
+ C/LzmaEnc.c
+ C/Ppmd7.c
+ C/Ppmd7Dec.c )
if( WIN32 )
set( LZMA_FILES ${LZMA_FILES} C/LzFindMt.c C/Threads.c )
diff --git a/lzma/history.txt b/lzma/history.txt
index 36d01d7d96..6abb8248cd 100644
--- a/lzma/history.txt
+++ b/lzma/history.txt
@@ -1,6 +1,62 @@
HISTORY of the LZMA SDK
-----------------------
+15.12 2015-11-19
+-------------------------
+- The BUG in C version of 7z decoder was fixed:
+ 7zDec.c : SzDecodeLzma2()
+ 7z decoder could mistakenly report about decoding error for some 7z archives
+ that use LZMA2 compression method.
+ The probability to get that mistaken decoding error report was about
+ one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size).
+- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed:
+ 7zArcIn.c : SzReadHeader2()
+ 7z decoder worked incorrectly for 7z archives that contain
+ empty solid blocks, that can be placed to 7z archive, if some file is
+ unavailable for reading during archive creation.
+
+
+15.09 beta 2015-10-16
+-------------------------
+- The BUG in LZMA / LZMA2 encoding code was fixed.
+ The BUG in LzFind.c::MatchFinder_ReadBlock() function.
+ If input data size is larger than (4 GiB - dictionary_size),
+ the following code worked incorrectly:
+ - LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions
+ for compressing from memory to memory.
+ That BUG is not related to LZMA encoder version that works via streams.
+ - LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if
+ default value of chunk size (CLzma2EncProps::blockSize) is changed
+ to value larger than (4 GiB - dictionary_size).
+
+
+9.38 beta 2015-01-03
+-------------------------
+- The BUG in 9.31-9.37 was fixed:
+ IArchiveGetRawProps interface was disabled for 7z archives.
+- The BUG in 9.26-9.36 was fixed:
+ Some code in CPP\7zip\Archive\7z\ worked correctly only under Windows.
+
+
+9.36 beta 2014-12-26
+-------------------------
+- The BUG in command line version was fixed:
+ 7-Zip created temporary archive in current folder during update archive
+ operation, if -w{Path} switch was not specified.
+ The fixed 7-Zip creates temporary archive in folder that contains updated archive.
+- The BUG in 9.33-9.35 was fixed:
+ 7-Zip silently ignored file reading errors during 7z or gz archive creation,
+ and the created archive contained only part of file that was read before error.
+ The fixed 7-Zip stops archive creation and it reports about error.
+
+
+9.35 beta 2014-12-07
+-------------------------
+- 7zr.exe now support AES encryption.
+- SFX mudules were added to LZMA SDK
+- Some bugs were fixed.
+
+
9.21 beta 2011-04-11
-------------------------
- New class FString for file names at file systems.
diff --git a/lzma/lzma.txt b/lzma/lzma.txt
index 9d3cef0031..4e74e8b5b7 100644
--- a/lzma/lzma.txt
+++ b/lzma/lzma.txt
@@ -1,18 +1,27 @@
-LZMA SDK 9.22
--------------
+LZMA SDK 15.13
+--------------
-LZMA SDK provides the documentation, samples, header files, libraries,
-and tools you need to develop applications that use LZMA compression.
-
-LZMA is default and general compression method of 7z format
-in 7-Zip compression program (www.7-zip.org). LZMA provides high
-compression ratio and very fast decompression.
+LZMA SDK provides the documentation, samples, header files,
+libraries, and tools you need to develop applications that
+use 7z / LZMA / LZMA2 / XZ compression.
LZMA is an improved version of famous LZ77 compression algorithm.
It was improved in way of maximum increasing of compression ratio,
keeping high decompression speed and low memory requirements for
decompressing.
+LZMA2 is a LZMA based compression method. LZMA2 provides better
+multithreading support for compression than LZMA and some other improvements.
+
+7z is a file format for data compression and file archiving.
+7z is a main file format for 7-Zip compression program (www.7-zip.org).
+7z format supports different compression methods: LZMA, LZMA2 and others.
+7z also supports AES-256 based encryption.
+
+XZ is a file format for data compression that uses LZMA2 compression.
+XZ format provides additional features: SHA/CRC check, filters for
+improved compression ratio, splitting to blocks and streams,
+
LICENSE
@@ -24,8 +33,9 @@ Some code in LZMA SDK is based on public domain code from another developers:
1) PPMd var.H (2001): Dmitry Shkarin
2) SHA-256: Wei Dai (Crypto++ library)
-You can copy, modify, distribute and perform LZMA SDK code, even for commercial purposes,
-all without asking permission.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute the
+original LZMA SDK code, either in source code form or as a compiled binary, for
+any purpose, commercial or non-commercial, and by any means.
LZMA SDK code is compatible with open source licenses, for example, you can
include it to GNU GPL or GNU LGPL code.
@@ -34,10 +44,20 @@ include it to GNU GPL or GNU LGPL code.
LZMA SDK Contents
-----------------
-LZMA SDK includes:
+ Source code:
- - ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing
- - Compiled file->file LZMA compressing/decompressing program for Windows system
+ - C / C++ / C# / Java - LZMA compression and decompression
+ - C / C++ - LZMA2 compression and decompression
+ - C / C++ - XZ compression and decompression
+ - C - 7z decompression
+ - C++ - 7z compression and decompression
+ - C - small SFXs for installers (7z decompression)
+ - C++ - SFXs and SFXs for installers (7z decompression)
+
+ Precomiled binaries:
+
+ - console programs for lzma / 7z / xz compression and decompression
+ - SFX modules for installers.
UNIX/Linux version
@@ -51,70 +71,94 @@ In some UNIX/Linux versions you must compile LZMA with static libraries.
To compile with static libraries, you can use
LIB = -lm -static
+Also you can use p7zip (port of 7-Zip for POSIX systems like Unix or Linux):
+
+ http://p7zip.sourceforge.net/
+
Files
----------------------
-lzma.txt - LZMA SDK description (this file)
-7zFormat.txt - 7z Format description
-7zC.txt - 7z ANSI-C Decoder description
-methods.txt - Compression method IDs for .7z
-lzma.exe - Compiled file->file LZMA encoder/decoder for Windows
-7zr.exe - 7-Zip with 7z/lzma/xz support.
-history.txt - history of the LZMA SDK
+-----
+
+DOC/7zC.txt - 7z ANSI-C Decoder description
+DOC/7zFormat.txt - 7z Format description
+DOC/installer.txt - information about 7-Zip for installers
+DOC/lzma.txt - LZMA compression description
+DOC/lzma-sdk.txt - LZMA SDK description (this file)
+DOC/lzma-history.txt - history of LZMA SDK
+DOC/lzma-specification.txt - Specification of LZMA
+DOC/Methods.txt - Compression method IDs for .7z
+
+bin/installer/ - example script to create installer that uses SFX module,
+
+bin/7zdec.exe - simplified 7z archive decoder
+bin/7zr.exe - 7-Zip console program (reduced version)
+bin/x64/7zr.exe - 7-Zip console program (reduced version) (x64 version)
+bin/lzma.exe - file->file LZMA encoder/decoder for Windows
+bin/7zS2.sfx - small SFX module for installers (GUI version)
+bin/7zS2con.sfx - small SFX module for installers (Console version)
+bin/7zSD.sfx - SFX module for installers.
+
+
+7zDec.exe
+---------
+7zDec.exe is simplified 7z archive decoder.
+It supports only LZMA, LZMA2, and PPMd methods.
+7zDec decodes whole solid block from 7z archive to RAM.
+The RAM consumption can be high.
+
+
Source code structure
---------------------
-C/ - C files
- 7zCrc*.* - CRC code
- Alloc.* - Memory allocation functions
- Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
- LzFind.* - Match finder for LZ (LZMA) encoders
- LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding
- LzHash.h - Additional file for LZ match finder
- LzmaDec.* - LZMA decoding
- LzmaEnc.* - LZMA encoding
- LzmaLib.* - LZMA Library for DLL calling
- Types.h - Basic types for another .c files
- Threads.* - The code for multithreading.
- LzmaLib - LZMA Library (.DLL for Windows)
-
- LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder).
+Asm/ - asm files (optimized code for CRC calculation and Intel-AES encryption)
- Archive - files related to archiving
- 7z - 7z ANSI-C Decoder
+C/ - C files (compression / decompression and other)
+ Util/
+ 7z - 7z decoder program (decoding 7z files)
+ Lzma - LZMA program (file->file LZMA encoder/decoder).
+ LzmaLib - LZMA library (.DLL for Windows)
+ SfxSetup - small SFX module for installers
CPP/ -- CPP files
Common - common files for C++ projects
Windows - common files for Windows related code
- 7zip - files related to 7-Zip Project
-
- Common - common files for 7-Zip
-
- Compress - files related to compression/decompression
+ 7zip - files related to 7-Zip
Archive - files related to archiving
Common - common files for archive handling
7z - 7z C++ Encoder/Decoder
- Bundles - Modules that are bundles of other modules
+ Bundles - Modules that are bundles of other modules (files)
- Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2
- LzmaCon - lzma.exe: LZMA compression/decompression
- Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2
- Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2.
+ Alone7z - 7zr.exe: Standalone 7-Zip console program (reduced version)
+ Format7zExtractR - 7zxr.dll: Reduced version of 7z DLL: extracting from 7z/LZMA/BCJ/BCJ2.
+ Format7zR - 7zr.dll: Reduced version of 7z DLL: extracting/compressing to 7z/LZMA/BCJ/BCJ2
+ LzmaCon - lzma.exe: LZMA compression/decompression
+ LzmaSpec - example code for LZMA Specification
+ SFXCon - 7zCon.sfx: Console 7z SFX module
+ SFXSetup - 7zS.sfx: 7z SFX module for installers
+ SFXWin - 7z.sfx: GUI 7z SFX module
- UI - User Interface files
+ Common - common files for 7-Zip
+
+ Compress - files for compression/decompression
+
+ Crypto - files for encryption / decompression
+
+ UI - User Interface files
- Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll
+ Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll
Common - Common UI files
- Console - Code for console archiver
-
+ Console - Code for console program (7z.exe)
+ Explorer - Some code from 7-Zip Shell extension
+ FileManager - Some GUI code from 7-Zip File Manager
+ GUI - Some GUI code from 7-Zip
CS/ - C# files
@@ -134,8 +178,9 @@ Java/ - Java files
RangeCoder - Range Coder (special code of compression/decompression)
-C/C++ source code of LZMA SDK is part of 7-Zip project.
-7-Zip source code can be downloaded from 7-Zip's SourceForge page:
+Note:
+ Asm / C / C++ source code of LZMA SDK is part of 7-Zip's source code.
+ 7-Zip's source code can be downloaded from 7-Zip's SourceForge page:
http://sourceforge.net/projects/sevenzip/
@@ -146,8 +191,8 @@ LZMA features
- Variable dictionary size (up to 1 GB)
- Estimated compressing speed: about 2 MB/s on 2 GHz CPU
- Estimated decompressing speed:
- - 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64
- - 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC
+ - 20-30 MB/s on modern 2 GHz cpu
+ - 1-2 MB/s on 200 MHz simple RISC cpu: (ARM, MIPS, PowerPC)
- Small memory requirements for decompressing (16 KB + DictionarySize)
- Small code size for decompressing: 5-8 KB
@@ -156,7 +201,7 @@ implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).
Some critical operations that affect the speed of LZMA decompression:
1) 32*16 bit integer multiply
- 2) Misspredicted branches (penalty mostly depends from pipeline length)
+ 2) Mispredicted branches (penalty mostly depends from pipeline length)
3) 32-bit shift and arithmetic operations
The speed of LZMA decompressing mostly depends from CPU speed.
@@ -304,298 +349,6 @@ compressible.
For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.
-LZMA compressed file format
----------------------------
-Offset Size Description
- 0 1 Special LZMA properties (lc,lp, pb in encoded form)
- 1 4 Dictionary size (little endian)
- 5 8 Uncompressed size (little endian). -1 means unknown size
- 13 Compressed data
-
-
-ANSI-C LZMA Decoder
-~~~~~~~~~~~~~~~~~~~
-
-Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58.
-If you want to use old interfaces you can download previous version of LZMA SDK
-from sourceforge.net site.
-
-To use ANSI-C LZMA Decoder you need the following files:
-1) LzmaDec.h + LzmaDec.c + Types.h
-LzmaUtil/LzmaUtil.c is example application that uses these files.
-
-
-Memory requirements for LZMA decoding
--------------------------------------
-
-Stack usage of LZMA decoding function for local variables is not
-larger than 200-400 bytes.
-
-LZMA Decoder uses dictionary buffer and internal state structure.
-Internal state structure consumes
- state_size = (4 + (1.5 << (lc + lp))) KB
-by default (lc=3, lp=0), state_size = 16 KB.
-
-
-How To decompress data
-----------------------
-
-LZMA Decoder (ANSI-C version) now supports 2 interfaces:
-1) Single-call Decompressing
-2) Multi-call State Decompressing (zlib-like interface)
-
-You must use external allocator:
-Example:
-void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
-void SzFree(void *p, void *address) { p = p; free(address); }
-ISzAlloc alloc = { SzAlloc, SzFree };
-
-You can use p = p; operator to disable compiler warnings.
-
-
-Single-call Decompressing
--------------------------
-When to use: RAM->RAM decompressing
-Compile files: LzmaDec.h + LzmaDec.c + Types.h
-Compile defines: no defines
-Memory Requirements:
- - Input buffer: compressed size
- - Output buffer: uncompressed size
- - LZMA Internal Structures: state_size (16 KB for default settings)
-
-Interface:
- int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
- ELzmaStatus *status, ISzAlloc *alloc);
- In:
- dest - output data
- destLen - output data size
- src - input data
- srcLen - input data size
- propData - LZMA properties (5 bytes)
- propSize - size of propData buffer (5 bytes)
- finishMode - It has meaning only if the decoding reaches output limit (*destLen).
- LZMA_FINISH_ANY - Decode just destLen bytes.
- LZMA_FINISH_END - Stream must be finished after (*destLen).
- You can use LZMA_FINISH_END, when you know that
- current output buffer covers last bytes of stream.
- alloc - Memory allocator.
-
- Out:
- destLen - processed output size
- srcLen - processed input size
-
- Output:
- SZ_OK
- status:
- LZMA_STATUS_FINISHED_WITH_MARK
- LZMA_STATUS_NOT_FINISHED
- LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
- SZ_ERROR_DATA - Data error
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_UNSUPPORTED - Unsupported properties
- SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
-
- If LZMA decoder sees end_marker before reaching output limit, it returns OK result,
- and output value of destLen will be less than output buffer size limit.
-
- You can use multiple checks to test data integrity after full decompression:
- 1) Check Result and "status" variable.
- 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
- 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
- You must use correct finish mode in that case. */
-
-
-Multi-call State Decompressing (zlib-like interface)
-----------------------------------------------------
-
-When to use: file->file decompressing
-Compile files: LzmaDec.h + LzmaDec.c + Types.h
-
-Memory Requirements:
- - Buffer for input stream: any size (for example, 16 KB)
- - Buffer for output stream: any size (for example, 16 KB)
- - LZMA Internal Structures: state_size (16 KB for default settings)
- - LZMA dictionary (dictionary size is encoded in LZMA properties header)
-
-1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header:
- unsigned char header[LZMA_PROPS_SIZE + 8];
- ReadFile(inFile, header, sizeof(header)
-
-2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties
-
- CLzmaDec state;
- LzmaDec_Constr(&state);
- res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
- if (res != SZ_OK)
- return res;
-
-3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop
-
- LzmaDec_Init(&state);
- for (;;)
- {
- ...
- int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode);
- ...
- }
-
-
-4) Free all allocated structures
- LzmaDec_Free(&state, &g_Alloc);
-
-For full code example, look at C/LzmaUtil/LzmaUtil.c code.
-
-
-How To compress data
---------------------
-
-Compile files: LzmaEnc.h + LzmaEnc.c + Types.h +
-LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h
-
-Memory Requirements:
- - (dictSize * 11.5 + 6 MB) + state_size
-
-Lzma Encoder can use two memory allocators:
-1) alloc - for small arrays.
-2) allocBig - for big arrays.
-
-For example, you can use Large RAM Pages (2 MB) in allocBig allocator for
-better compression speed. Note that Windows has bad implementation for
-Large RAM Pages.
-It's OK to use same allocator for alloc and allocBig.
-
-
-Single-call Compression with callbacks
---------------------------------------
-
-Check C/LzmaUtil/LzmaUtil.c as example,
-
-When to use: file->file decompressing
-
-1) you must implement callback structures for interfaces:
-ISeqInStream
-ISeqOutStream
-ICompressProgress
-ISzAlloc
-
-static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
-static void SzFree(void *p, void *address) { p = p; MyFree(address); }
-static ISzAlloc g_Alloc = { SzAlloc, SzFree };
-
- CFileSeqInStream inStream;
- CFileSeqOutStream outStream;
-
- inStream.funcTable.Read = MyRead;
- inStream.file = inFile;
- outStream.funcTable.Write = MyWrite;
- outStream.file = outFile;
-
-
-2) Create CLzmaEncHandle object;
-
- CLzmaEncHandle enc;
-
- enc = LzmaEnc_Create(&g_Alloc);
- if (enc == 0)
- return SZ_ERROR_MEM;
-
-
-3) initialize CLzmaEncProps properties;
-
- LzmaEncProps_Init(&props);
-
- Then you can change some properties in that structure.
-
-4) Send LZMA properties to LZMA Encoder
-
- res = LzmaEnc_SetProps(enc, &props);
-
-5) Write encoded properties to header
-
- Byte header[LZMA_PROPS_SIZE + 8];
- size_t headerSize = LZMA_PROPS_SIZE;
- UInt64 fileSize;
- int i;
-
- res = LzmaEnc_WriteProperties(enc, header, &headerSize);
- fileSize = MyGetFileLength(inFile);
- for (i = 0; i < 8; i++)
- header[headerSize++] = (Byte)(fileSize >> (8 * i));
- MyWriteFileAndCheck(outFile, header, headerSize)
-
-6) Call encoding function:
- res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
- NULL, &g_Alloc, &g_Alloc);
-
-7) Destroy LZMA Encoder Object
- LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
-
-
-If callback function return some error code, LzmaEnc_Encode also returns that code
-or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS.
-
-
-Single-call RAM->RAM Compression
---------------------------------
-
-Single-call RAM->RAM Compression is similar to Compression with callbacks,
-but you provide pointers to buffers instead of pointers to stream callbacks:
-
-HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
- CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
-
-Return code:
- SZ_OK - OK
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_PARAM - Incorrect paramater
- SZ_ERROR_OUTPUT_EOF - output buffer overflow
- SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
-
-
-
-Defines
--------
-
-_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code.
-
-_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for
- some structures will be doubled in that case.
-
-_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit.
-
-_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type.
-
-
-_7ZIP_PPMD_SUPPPORT - Define it if you don't want to support PPMD method in AMSI-C .7z decoder.
-
-
-C++ LZMA Encoder/Decoder
-~~~~~~~~~~~~~~~~~~~~~~~~
-C++ LZMA code use COM-like interfaces. So if you want to use it,
-you can study basics of COM/OLE.
-C++ LZMA code is just wrapper over ANSI-C code.
-
-
-C++ Notes
-~~~~~~~~~~~~~~~~~~~~~~~~
-If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling),
-you must check that you correctly work with "new" operator.
-7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator.
-So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator:
-operator new(size_t size)
-{
- void *p = ::malloc(size);
- if (p == 0)
- throw CNewException();
- return p;
-}
-If you use MSCV that throws exception for "new" operator, you can compile without
-"NewHandler.cpp". So standard exception will be used. Actually some code of
-7-Zip catches any exception in internal code and converts it to HRESULT code.
-So you don't need to catch CNewException, if you call COM interfaces of 7-Zip.
---
diff --git a/lzma/lzmalib.vcproj b/lzma/lzmalib.vcproj
index 2736f31a6a..f1e085f3d8 100644
--- a/lzma/lzmalib.vcproj
+++ b/lzma/lzmalib.vcproj
@@ -1,12 +1,11 @@
+
+
@@ -303,10 +306,6 @@
RelativePath=".\C\7zDec.c"
>
-
-
@@ -323,10 +322,18 @@
RelativePath=".\C\Bra86.c"
>
+
+
+
+
@@ -347,6 +354,14 @@
RelativePath=".\C\LzmaEnc.c"
>
+
+
+
+
@@ -381,10 +396,18 @@
RelativePath=".\C\Bra.h"
>
+
+
+
+
@@ -409,6 +432,18 @@
RelativePath=".\C\LzmaEnc.h"
>
+
+
+
+
+
+
diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt
index e79ae196be..611a667af1 100644
--- a/specs/udmf_zdoom.txt
+++ b/specs/udmf_zdoom.txt
@@ -203,7 +203,18 @@ Note: All fields default to false unless mentioned otherwise.
// sound sequence thing in the sector will override this property.
hidden = ; // if true this sector will not be drawn on the textured automap.
waterzone = ; // Sector is under water and swimmable
- moreids = ; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505")
+ moreids = ; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505")
+ damageamount = ; // Amount of damage inflicted by this sector, default = 0. If this is 0, all other damage properties will be ignored.
+ // Setting damage through these properties will override any damage set through 'special'.
+ // Setting damageamount to a negative value will create a healing sector.
+ damagetype = ; // Damage type for sector damage, Default = "None". (generic damage)
+ damageinterval = ; // Interval in tics between damage application, default = 32.
+ leakiness = ; // Probability of leaking through radiation suit (0 = never, 256 = always), default = 0.
+ damageterraineffect = ; // Will spawn a terrain splash when damage is inflicted. Default = false.
+ damagehazard = ; // Changes damage model to Strife's delayed damage for the given sector. Default = false.
+ floorterrain = ; // Sets the terrain for the sector's floor. Default = 'use the flat texture's terrain definition.'
+ ceilingterrain = ; // Sets the terrain for the sector's ceiling. Default = 'use the flat texture's terrain definition.'
+
* Note about dropactors
@@ -377,6 +388,10 @@ Changed language describing the DIALOGUE lump to mention USDF as an option.
1.25 19.04.2015
Added 'moreids' for linedefs and sectors.
+1.26 05.01.2016
+added clarification about character encoding
+added sector damage properties.
+
===============================================================================
EOF
===============================================================================
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 35d8f43811..cac4e59753 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -591,9 +591,7 @@ set( PLAT_WIN32_SOURCES
set( PLAT_POSIX_SOURCES
posix/i_cd.cpp
posix/i_movie.cpp
- posix/i_steam.cpp
- posix/i_system.cpp
- posix/st_start.cpp )
+ posix/i_steam.cpp )
set( PLAT_SDL_SOURCES
posix/sdl/crashcatcher.c
posix/sdl/hardware.cpp
@@ -601,8 +599,10 @@ set( PLAT_SDL_SOURCES
posix/sdl/i_input.cpp
posix/sdl/i_joystick.cpp
posix/sdl/i_main.cpp
+ posix/sdl/i_system.cpp
posix/sdl/i_timer.cpp
- posix/sdl/sdlvideo.cpp )
+ posix/sdl/sdlvideo.cpp
+ posix/sdl/st_start.cpp )
set( PLAT_OSX_SOURCES
posix/osx/iwadpicker_cocoa.mm
posix/osx/zdoom.icns )
@@ -611,8 +611,11 @@ set( PLAT_COCOA_SOURCES
posix/cocoa/i_input.mm
posix/cocoa/i_joystick.cpp
posix/cocoa/i_main.mm
+ posix/cocoa/i_system.mm
posix/cocoa/i_timer.cpp
- posix/cocoa/i_video.mm )
+ posix/cocoa/i_video.mm
+ posix/cocoa/st_console.mm
+ posix/cocoa/st_start.mm )
if( WIN32 )
set( SYSTEM_SOURCES_DIR win32 )
@@ -1005,6 +1008,8 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
wi_stuff.cpp
zstrformat.cpp
zstring.cpp
+ GuillotineBinPack.cpp
+ SkylineBinPack.cpp
g_doom/a_doommisc.cpp
g_heretic/a_hereticmisc.cpp
g_hexen/a_hexenmisc.cpp
diff --git a/src/GuillotineBinPack.cpp b/src/GuillotineBinPack.cpp
new file mode 100644
index 0000000000..5efbbf8a18
--- /dev/null
+++ b/src/GuillotineBinPack.cpp
@@ -0,0 +1,634 @@
+/** @file GuillotineBinPack.cpp
+ @author Jukka Jylänki
+
+ @brief Implements different bin packer algorithms that use the GUILLOTINE data structure.
+
+ This work is released to Public Domain, do whatever you want with it.
+*/
+
+#include
+#include
+#include "templates.h"
+#include "GuillotineBinPack.h"
+
+using namespace std;
+
+GuillotineBinPack::GuillotineBinPack()
+:binWidth(0),
+binHeight(0)
+{
+}
+
+GuillotineBinPack::GuillotineBinPack(int width, int height)
+{
+ Init(width, height);
+}
+
+void GuillotineBinPack::Init(int width, int height)
+{
+ binWidth = width;
+ binHeight = height;
+
+#ifdef _DEBUG
+ disjointRects.Clear();
+#endif
+
+ // Clear any memory of previously packed rectangles.
+ usedRectangles.Clear();
+
+ // We start with a single big free rectangle that spans the whole bin.
+ Rect n;
+ n.x = 0;
+ n.y = 0;
+ n.width = width;
+ n.height = height;
+
+ freeRectangles.Clear();
+ freeRectangles.Push(n);
+}
+
+void GuillotineBinPack::Insert(TArray &rects, TArray &dst, bool merge,
+ FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
+{
+ dst.Clear();
+
+ // Remember variables about the best packing choice we have made so far during the iteration process.
+ int bestFreeRect = 0;
+ int bestRect = 0;
+ bool bestFlipped = false;
+
+ // Pack rectangles one at a time until we have cleared the rects array of all rectangles.
+ // rects will get destroyed in the process.
+ while(rects.Size() > 0)
+ {
+ // Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better.
+ int bestScore = INT_MAX;
+
+ for(unsigned i = 0; i < freeRectangles.Size(); ++i)
+ {
+ for(unsigned j = 0; j < rects.Size(); ++j)
+ {
+ // If this rectangle is a perfect match, we pick it instantly.
+ if (rects[j].width == freeRectangles[i].width && rects[j].height == freeRectangles[i].height)
+ {
+ bestFreeRect = i;
+ bestRect = j;
+ bestFlipped = false;
+ bestScore = INT_MIN;
+ i = freeRectangles.Size(); // Force a jump out of the outer loop as well - we got an instant fit.
+ break;
+ }
+ // If flipping this rectangle is a perfect match, pick that then.
+ else if (rects[j].height == freeRectangles[i].width && rects[j].width == freeRectangles[i].height)
+ {
+ bestFreeRect = i;
+ bestRect = j;
+ bestFlipped = true;
+ bestScore = INT_MIN;
+ i = freeRectangles.Size(); // Force a jump out of the outer loop as well - we got an instant fit.
+ break;
+ }
+ // Try if we can fit the rectangle upright.
+ else if (rects[j].width <= freeRectangles[i].width && rects[j].height <= freeRectangles[i].height)
+ {
+ int score = ScoreByHeuristic(rects[j].width, rects[j].height, freeRectangles[i], rectChoice);
+ if (score < bestScore)
+ {
+ bestFreeRect = i;
+ bestRect = j;
+ bestFlipped = false;
+ bestScore = score;
+ }
+ }
+ // If not, then perhaps flipping sideways will make it fit?
+ else if (rects[j].height <= freeRectangles[i].width && rects[j].width <= freeRectangles[i].height)
+ {
+ int score = ScoreByHeuristic(rects[j].height, rects[j].width, freeRectangles[i], rectChoice);
+ if (score < bestScore)
+ {
+ bestFreeRect = i;
+ bestRect = j;
+ bestFlipped = true;
+ bestScore = score;
+ }
+ }
+ }
+ }
+
+ // If we didn't manage to find any rectangle to pack, abort.
+ if (bestScore == INT_MAX)
+ return;
+
+ // Otherwise, we're good to go and do the actual packing.
+ Rect newNode;
+ newNode.x = freeRectangles[bestFreeRect].x;
+ newNode.y = freeRectangles[bestFreeRect].y;
+ newNode.width = rects[bestRect].width;
+ newNode.height = rects[bestRect].height;
+
+ if (bestFlipped)
+ std::swap(newNode.width, newNode.height);
+
+ // Remove the free space we lost in the bin.
+ SplitFreeRectByHeuristic(freeRectangles[bestFreeRect], newNode, splitMethod);
+ freeRectangles.Delete(bestFreeRect);
+
+ // Remove the rectangle we just packed from the input list.
+ rects.Delete(bestRect);
+
+ // Perform a Rectangle Merge step if desired.
+ if (merge)
+ MergeFreeList();
+
+ // Remember the new used rectangle.
+ usedRectangles.Push(newNode);
+
+ // Check that we're really producing correct packings here.
+ assert(disjointRects.Add(newNode) == true);
+ }
+}
+
+/// @return True if r fits inside freeRect (possibly rotated).
+bool Fits(const RectSize &r, const Rect &freeRect)
+{
+ return (r.width <= freeRect.width && r.height <= freeRect.height) ||
+ (r.height <= freeRect.width && r.width <= freeRect.height);
+}
+
+/// @return True if r fits perfectly inside freeRect, i.e. the leftover area is 0.
+bool FitsPerfectly(const RectSize &r, const Rect &freeRect)
+{
+ return (r.width == freeRect.width && r.height == freeRect.height) ||
+ (r.height == freeRect.width && r.width == freeRect.height);
+}
+
+/*
+// A helper function for GUILLOTINE-MAXFITTING. Counts how many rectangles fit into the given rectangle
+// after it has been split.
+void CountNumFitting(const Rect &freeRect, int width, int height, const TArray &rects,
+ int usedRectIndex, bool splitHorizontal, int &score1, int &score2)
+{
+ const int w = freeRect.width - width;
+ const int h = freeRect.height - height;
+
+ Rect bottom;
+ bottom.x = freeRect.x;
+ bottom.y = freeRect.y + height;
+ bottom.height = h;
+
+ Rect right;
+ right.x = freeRect.x + width;
+ right.y = freeRect.y;
+ right.width = w;
+
+ if (splitHorizontal)
+ {
+ bottom.width = freeRect.width;
+ right.height = height;
+ }
+ else // Split vertically
+ {
+ bottom.width = width;
+ right.height = freeRect.height;
+ }
+
+ int fitBottom = 0;
+ int fitRight = 0;
+ for(size_t i = 0; i < rects.size(); ++i)
+ if (i != usedRectIndex)
+ {
+ if (FitsPerfectly(rects[i], bottom))
+ fitBottom |= 0x10000000;
+ if (FitsPerfectly(rects[i], right))
+ fitRight |= 0x10000000;
+
+ if (Fits(rects[i], bottom))
+ ++fitBottom;
+ if (Fits(rects[i], right))
+ ++fitRight;
+ }
+
+ score1 = min(fitBottom, fitRight);
+ score2 = max(fitBottom, fitRight);
+}
+*/
+/*
+// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice.
+void GuillotineBinPack::InsertMaxFitting(TArray &rects, TArray &dst, bool merge,
+ FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
+{
+ dst.clear();
+ int bestRect = 0;
+ bool bestFlipped = false;
+ bool bestSplitHorizontal = false;
+
+ // Pick rectangles one at a time and pack the one that leaves the most choices still open.
+ while(rects.size() > 0 && freeRectangles.size() > 0)
+ {
+ int bestScore1 = -1;
+ int bestScore2 = -1;
+
+ ///\todo Different sort predicates.
+ clb::sort::QuickSort(&freeRectangles[0], freeRectangles.size(), CompareRectShortSide);
+
+ Rect &freeRect = freeRectangles[0];
+
+ for(size_t j = 0; j < rects.size(); ++j)
+ {
+ int score1;
+ int score2;
+
+ if (rects[j].width == freeRect.width && rects[j].height == freeRect.height)
+ {
+ bestRect = j;
+ bestFlipped = false;
+ bestScore1 = bestScore2 = std::numeric_limits::max();
+ break;
+ }
+ else if (rects[j].width <= freeRect.width && rects[j].height <= freeRect.height)
+ {
+ CountNumFitting(freeRect, rects[j].width, rects[j].height, rects, j, false, score1, score2);
+
+ if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
+ {
+ bestRect = j;
+ bestScore1 = score1;
+ bestScore2 = score2;
+ bestFlipped = false;
+ bestSplitHorizontal = false;
+ }
+
+ CountNumFitting(freeRect, rects[j].width, rects[j].height, rects, j, true, score1, score2);
+
+ if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
+ {
+ bestRect = j;
+ bestScore1 = score1;
+ bestScore2 = score2;
+ bestFlipped = false;
+ bestSplitHorizontal = true;
+ }
+ }
+
+ if (rects[j].height == freeRect.width && rects[j].width == freeRect.height)
+ {
+ bestRect = j;
+ bestFlipped = true;
+ bestScore1 = bestScore2 = std::numeric_limits::max();
+ break;
+ }
+ else if (rects[j].height <= freeRect.width && rects[j].width <= freeRect.height)
+ {
+ CountNumFitting(freeRect, rects[j].height, rects[j].width, rects, j, false, score1, score2);
+
+ if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
+ {
+ bestRect = j;
+ bestScore1 = score1;
+ bestScore2 = score2;
+ bestFlipped = true;
+ bestSplitHorizontal = false;
+ }
+
+ CountNumFitting(freeRect, rects[j].height, rects[j].width, rects, j, true, score1, score2);
+
+ if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
+ {
+ bestRect = j;
+ bestScore1 = score1;
+ bestScore2 = score2;
+ bestFlipped = true;
+ bestSplitHorizontal = true;
+ }
+ }
+ }
+
+ if (bestScore1 >= 0)
+ {
+ Rect newNode;
+ newNode.x = freeRect.x;
+ newNode.y = freeRect.y;
+ newNode.width = rects[bestRect].width;
+ newNode.height = rects[bestRect].height;
+ if (bestFlipped)
+ std::swap(newNode.width, newNode.height);
+
+ assert(disjointRects.Disjoint(newNode));
+ SplitFreeRectAlongAxis(freeRect, newNode, bestSplitHorizontal);
+
+ rects.erase(rects.begin() + bestRect);
+
+ if (merge)
+ MergeFreeList();
+
+ usedRectangles.push_back(newNode);
+#ifdef _DEBUG
+ disjointRects.Add(newNode);
+#endif
+ }
+
+ freeRectangles.erase(freeRectangles.begin());
+ }
+}
+*/
+
+Rect GuillotineBinPack::Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice,
+ GuillotineSplitHeuristic splitMethod)
+{
+ // Find where to put the new rectangle.
+ int freeNodeIndex = 0;
+ Rect newRect = FindPositionForNewNode(width, height, rectChoice, &freeNodeIndex);
+
+ // Abort if we didn't have enough space in the bin.
+ if (newRect.height == 0)
+ return newRect;
+
+ // Remove the space that was just consumed by the new rectangle.
+ SplitFreeRectByHeuristic(freeRectangles[freeNodeIndex], newRect, splitMethod);
+ freeRectangles.Delete(freeNodeIndex);
+
+ // Perform a Rectangle Merge step if desired.
+ if (merge)
+ MergeFreeList();
+
+ // Remember the new used rectangle.
+ usedRectangles.Push(newRect);
+
+ // Check that we're really producing correct packings here.
+ assert(disjointRects.Add(newRect) == true);
+
+ return newRect;
+}
+
+/// Computes the ratio of used surface area to the total bin area.
+float GuillotineBinPack::Occupancy() const
+{
+ ///\todo The occupancy rate could be cached/tracked incrementally instead
+ /// of looping through the list of packed rectangles here.
+ unsigned long usedSurfaceArea = 0;
+ for(unsigned i = 0; i < usedRectangles.Size(); ++i)
+ usedSurfaceArea += usedRectangles[i].width * usedRectangles[i].height;
+
+ return (float)usedSurfaceArea / (binWidth * binHeight);
+}
+
+/// Returns the heuristic score value for placing a rectangle of size width*height into freeRect. Does not try to rotate.
+int GuillotineBinPack::ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice)
+{
+ switch(rectChoice)
+ {
+ case RectBestAreaFit: return ScoreBestAreaFit(width, height, freeRect);
+ case RectBestShortSideFit: return ScoreBestShortSideFit(width, height, freeRect);
+ case RectBestLongSideFit: return ScoreBestLongSideFit(width, height, freeRect);
+ case RectWorstAreaFit: return ScoreWorstAreaFit(width, height, freeRect);
+ case RectWorstShortSideFit: return ScoreWorstShortSideFit(width, height, freeRect);
+ case RectWorstLongSideFit: return ScoreWorstLongSideFit(width, height, freeRect);
+ default: assert(false); return INT_MAX;
+ }
+}
+
+int GuillotineBinPack::ScoreBestAreaFit(int width, int height, const Rect &freeRect)
+{
+ return freeRect.width * freeRect.height - width * height;
+}
+
+int GuillotineBinPack::ScoreBestShortSideFit(int width, int height, const Rect &freeRect)
+{
+ int leftoverHoriz = abs(freeRect.width - width);
+ int leftoverVert = abs(freeRect.height - height);
+ int leftover = MIN(leftoverHoriz, leftoverVert);
+ return leftover;
+}
+
+int GuillotineBinPack::ScoreBestLongSideFit(int width, int height, const Rect &freeRect)
+{
+ int leftoverHoriz = abs(freeRect.width - width);
+ int leftoverVert = abs(freeRect.height - height);
+ int leftover = MAX(leftoverHoriz, leftoverVert);
+ return leftover;
+}
+
+int GuillotineBinPack::ScoreWorstAreaFit(int width, int height, const Rect &freeRect)
+{
+ return -ScoreBestAreaFit(width, height, freeRect);
+}
+
+int GuillotineBinPack::ScoreWorstShortSideFit(int width, int height, const Rect &freeRect)
+{
+ return -ScoreBestShortSideFit(width, height, freeRect);
+}
+
+int GuillotineBinPack::ScoreWorstLongSideFit(int width, int height, const Rect &freeRect)
+{
+ return -ScoreBestLongSideFit(width, height, freeRect);
+}
+
+Rect GuillotineBinPack::FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex)
+{
+ Rect bestNode;
+ memset(&bestNode, 0, sizeof(Rect));
+
+ int bestScore = INT_MAX;
+
+ /// Try each free rectangle to find the best one for placement.
+ for(unsigned i = 0; i < freeRectangles.Size(); ++i)
+ {
+ // If this is a perfect fit upright, choose it immediately.
+ if (width == freeRectangles[i].width && height == freeRectangles[i].height)
+ {
+ bestNode.x = freeRectangles[i].x;
+ bestNode.y = freeRectangles[i].y;
+ bestNode.width = width;
+ bestNode.height = height;
+ bestScore = INT_MIN;
+ *nodeIndex = i;
+ assert(disjointRects.Disjoint(bestNode));
+ break;
+ }
+ // If this is a perfect fit sideways, choose it.
+/* else if (height == freeRectangles[i].width && width == freeRectangles[i].height)
+ {
+ bestNode.x = freeRectangles[i].x;
+ bestNode.y = freeRectangles[i].y;
+ bestNode.width = height;
+ bestNode.height = width;
+ bestScore = INT_MIN;
+ *nodeIndex = i;
+ assert(disjointRects.Disjoint(bestNode));
+ break;
+ }
+*/ // Does the rectangle fit upright?
+ else if (width <= freeRectangles[i].width && height <= freeRectangles[i].height)
+ {
+ int score = ScoreByHeuristic(width, height, freeRectangles[i], rectChoice);
+
+ if (score < bestScore)
+ {
+ bestNode.x = freeRectangles[i].x;
+ bestNode.y = freeRectangles[i].y;
+ bestNode.width = width;
+ bestNode.height = height;
+ bestScore = score;
+ *nodeIndex = i;
+ assert(disjointRects.Disjoint(bestNode));
+ }
+ }
+ // Does the rectangle fit sideways?
+/* else if (height <= freeRectangles[i].width && width <= freeRectangles[i].height)
+ {
+ int score = ScoreByHeuristic(height, width, freeRectangles[i], rectChoice);
+
+ if (score < bestScore)
+ {
+ bestNode.x = freeRectangles[i].x;
+ bestNode.y = freeRectangles[i].y;
+ bestNode.width = height;
+ bestNode.height = width;
+ bestScore = score;
+ *nodeIndex = i;
+ assert(disjointRects.Disjoint(bestNode));
+ }
+ }
+*/ }
+ return bestNode;
+}
+
+void GuillotineBinPack::SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method)
+{
+ // Compute the lengths of the leftover area.
+ const int w = freeRect.width - placedRect.width;
+ const int h = freeRect.height - placedRect.height;
+
+ // Placing placedRect into freeRect results in an L-shaped free area, which must be split into
+ // two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line.
+ // We have two choices: horizontal or vertical.
+
+ // Use the given heuristic to decide which choice to make.
+
+ bool splitHorizontal;
+ switch(method)
+ {
+ case SplitShorterLeftoverAxis:
+ // Split along the shorter leftover axis.
+ splitHorizontal = (w <= h);
+ break;
+ case SplitLongerLeftoverAxis:
+ // Split along the longer leftover axis.
+ splitHorizontal = (w > h);
+ break;
+ case SplitMinimizeArea:
+ // Maximize the larger area == minimize the smaller area.
+ // Tries to make the single bigger rectangle.
+ splitHorizontal = (placedRect.width * h > w * placedRect.height);
+ break;
+ case SplitMaximizeArea:
+ // Maximize the smaller area == minimize the larger area.
+ // Tries to make the rectangles more even-sized.
+ splitHorizontal = (placedRect.width * h <= w * placedRect.height);
+ break;
+ case SplitShorterAxis:
+ // Split along the shorter total axis.
+ splitHorizontal = (freeRect.width <= freeRect.height);
+ break;
+ case SplitLongerAxis:
+ // Split along the longer total axis.
+ splitHorizontal = (freeRect.width > freeRect.height);
+ break;
+ default:
+ splitHorizontal = true;
+ assert(false);
+ }
+
+ // Perform the actual split.
+ SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal);
+}
+
+/// This function will add the two generated rectangles into the freeRectangles array. The caller is expected to
+/// remove the original rectangle from the freeRectangles array after that.
+void GuillotineBinPack::SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal)
+{
+ // Form the two new rectangles.
+ Rect bottom;
+ bottom.x = freeRect.x;
+ bottom.y = freeRect.y + placedRect.height;
+ bottom.height = freeRect.height - placedRect.height;
+
+ Rect right;
+ right.x = freeRect.x + placedRect.width;
+ right.y = freeRect.y;
+ right.width = freeRect.width - placedRect.width;
+
+ if (splitHorizontal)
+ {
+ bottom.width = freeRect.width;
+ right.height = placedRect.height;
+ }
+ else // Split vertically
+ {
+ bottom.width = placedRect.width;
+ right.height = freeRect.height;
+ }
+
+ // Add the new rectangles into the free rectangle pool if they weren't degenerate.
+ if (bottom.width > 0 && bottom.height > 0)
+ freeRectangles.Push(bottom);
+ if (right.width > 0 && right.height > 0)
+ freeRectangles.Push(right);
+
+ assert(disjointRects.Disjoint(bottom));
+ assert(disjointRects.Disjoint(right));
+}
+
+void GuillotineBinPack::MergeFreeList()
+{
+#ifdef _DEBUG
+ DisjointRectCollection test;
+ for(unsigned i = 0; i < freeRectangles.Size(); ++i)
+ assert(test.Add(freeRectangles[i]) == true);
+#endif
+
+ // Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one.
+ // Note that we miss any opportunities to merge three rectangles into one. (should call this function again to detect that)
+ for(unsigned i = 0; i < freeRectangles.Size(); ++i)
+ for(unsigned j = i+1; j < freeRectangles.Size(); ++j)
+ {
+ if (freeRectangles[i].width == freeRectangles[j].width && freeRectangles[i].x == freeRectangles[j].x)
+ {
+ if (freeRectangles[i].y == freeRectangles[j].y + freeRectangles[j].height)
+ {
+ freeRectangles[i].y -= freeRectangles[j].height;
+ freeRectangles[i].height += freeRectangles[j].height;
+ freeRectangles.Delete(j);
+ --j;
+ }
+ else if (freeRectangles[i].y + freeRectangles[i].height == freeRectangles[j].y)
+ {
+ freeRectangles[i].height += freeRectangles[j].height;
+ freeRectangles.Delete(j);
+ --j;
+ }
+ }
+ else if (freeRectangles[i].height == freeRectangles[j].height && freeRectangles[i].y == freeRectangles[j].y)
+ {
+ if (freeRectangles[i].x == freeRectangles[j].x + freeRectangles[j].width)
+ {
+ freeRectangles[i].x -= freeRectangles[j].width;
+ freeRectangles[i].width += freeRectangles[j].width;
+ freeRectangles.Delete(j);
+ --j;
+ }
+ else if (freeRectangles[i].x + freeRectangles[i].width == freeRectangles[j].x)
+ {
+ freeRectangles[i].width += freeRectangles[j].width;
+ freeRectangles.Delete(j);
+ --j;
+ }
+ }
+ }
+
+#ifdef _DEBUG
+ test.Clear();
+ for(unsigned i = 0; i < freeRectangles.Size(); ++i)
+ assert(test.Add(freeRectangles[i]) == true);
+#endif
+}
diff --git a/src/GuillotineBinPack.h b/src/GuillotineBinPack.h
new file mode 100644
index 0000000000..54cd77a9ea
--- /dev/null
+++ b/src/GuillotineBinPack.h
@@ -0,0 +1,135 @@
+/** @file GuillotineBinPack.h
+ @author Jukka Jylänki
+
+ @brief Implements different bin packer algorithms that use the GUILLOTINE data structure.
+
+ This work is released to Public Domain, do whatever you want with it.
+*/
+#pragma once
+
+#include "tarray.h"
+
+#include "Rect.h"
+
+/** GuillotineBinPack implements different variants of bin packer algorithms that use the GUILLOTINE data structure
+ to keep track of the free space of the bin where rectangles may be placed. */
+class GuillotineBinPack
+{
+public:
+ /// The initial bin size will be (0,0). Call Init to set the bin size.
+ GuillotineBinPack();
+
+ /// Initializes a new bin of the given size.
+ GuillotineBinPack(int width, int height);
+
+ /// (Re)initializes the packer to an empty bin of width x height units. Call whenever
+ /// you need to restart with a new bin.
+ void Init(int width, int height);
+
+ /// Specifies the different choice heuristics that can be used when deciding which of the free subrectangles
+ /// to place the to-be-packed rectangle into.
+ enum FreeRectChoiceHeuristic
+ {
+ RectBestAreaFit, ///< -BAF
+ RectBestShortSideFit, ///< -BSSF
+ RectBestLongSideFit, ///< -BLSF
+ RectWorstAreaFit, ///< -WAF
+ RectWorstShortSideFit, ///< -WSSF
+ RectWorstLongSideFit ///< -WLSF
+ };
+
+ /// Specifies the different choice heuristics that can be used when the packer needs to decide whether to
+ /// subdivide the remaining free space in horizontal or vertical direction.
+ enum GuillotineSplitHeuristic
+ {
+ SplitShorterLeftoverAxis, ///< -SLAS
+ SplitLongerLeftoverAxis, ///< -LLAS
+ SplitMinimizeArea, ///< -MINAS, Try to make a single big rectangle at the expense of making the other small.
+ SplitMaximizeArea, ///< -MAXAS, Try to make both remaining rectangles as even-sized as possible.
+ SplitShorterAxis, ///< -SAS
+ SplitLongerAxis ///< -LAS
+ };
+
+ /// Inserts a single rectangle into the bin. The packer might rotate the rectangle, in which case the returned
+ /// struct will have the width and height values swapped.
+ /// @param merge If true, performs free Rectangle Merge procedure after packing the new rectangle. This procedure
+ /// tries to defragment the list of disjoint free rectangles to improve packing performance, but also takes up
+ /// some extra time.
+ /// @param rectChoice The free rectangle choice heuristic rule to use.
+ /// @param splitMethod The free rectangle split heuristic rule to use.
+ Rect Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
+
+ /// Inserts a list of rectangles into the bin.
+ /// @param rects The list of rectangles to add. This list will be destroyed in the packing process.
+ /// @param dst The outputted list of rectangles. Note that the indices will not correspond to the input indices.
+ /// @param merge If true, performs Rectangle Merge operations during the packing process.
+ /// @param rectChoice The free rectangle choice heuristic rule to use.
+ /// @param splitMethod The free rectangle split heuristic rule to use.
+ void Insert(TArray &rects, TArray &dst, bool merge,
+ FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
+
+// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice.
+// void InsertMaxFitting(TArray &rects, TArray &dst, bool merge,
+// FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
+
+ /// Computes the ratio of used/total surface area. 0.00 means no space is yet used, 1.00 means the whole bin is used.
+ float Occupancy() const;
+
+ /// Returns the internal list of disjoint rectangles that track the free area of the bin. You may alter this vector
+ /// any way desired, as long as the end result still is a list of disjoint rectangles.
+ TArray &GetFreeRectangles() { return freeRectangles; }
+
+ /// Returns the list of packed rectangles. You may alter this vector at will, for example, you can move a Rect from
+ /// this list to the Free Rectangles list to free up space on-the-fly, but notice that this causes fragmentation.
+ TArray &GetUsedRectangles() { return usedRectangles; }
+
+ /// Performs a Rectangle Merge operation. This procedure looks for adjacent free rectangles and merges them if they
+ /// can be represented with a single rectangle. Takes up Theta(|freeRectangles|^2) time.
+ void MergeFreeList();
+
+#ifdef _DEBUG
+ void DelDisjoint(const Rect &r) { disjointRects.Del(r); }
+#endif
+
+private:
+ int binWidth;
+ int binHeight;
+
+ /// Stores a list of all the rectangles that we have packed so far. This is used only to compute the Occupancy ratio,
+ /// so if you want to have the packer consume less memory, this can be removed.
+ TArray usedRectangles;
+
+ /// Stores a list of rectangles that represents the free area of the bin. This rectangles in this list are disjoint.
+ TArray freeRectangles;
+
+#ifdef _DEBUG
+ /// Used to track that the packer produces proper packings.
+ DisjointRectCollection disjointRects;
+#endif
+
+ /// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into.
+ /// Running time is Theta(|freeRectangles|).
+ /// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new
+ /// rect was placed.
+ /// @return A Rect structure that represents the placement of the new rect into the best free rectangle.
+ Rect FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex);
+
+ static int ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice);
+ // The following functions compute (penalty) score values if a rect of the given size was placed into the
+ // given free rectangle. In these score values, smaller is better.
+
+ static int ScoreBestAreaFit(int width, int height, const Rect &freeRect);
+ static int ScoreBestShortSideFit(int width, int height, const Rect &freeRect);
+ static int ScoreBestLongSideFit(int width, int height, const Rect &freeRect);
+
+ static int ScoreWorstAreaFit(int width, int height, const Rect &freeRect);
+ static int ScoreWorstShortSideFit(int width, int height, const Rect &freeRect);
+ static int ScoreWorstLongSideFit(int width, int height, const Rect &freeRect);
+
+ /// Splits the given L-shaped free rectangle into two new free rectangles after placedRect has been placed into it.
+ /// Determines the split axis by using the given heuristic.
+ void SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method);
+
+ /// Splits the given L-shaped free rectangle into two new free rectangles along the given fixed split axis.
+ void SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal);
+};
diff --git a/src/Rect.h b/src/Rect.h
new file mode 100644
index 0000000000..8b7ba1e2a6
--- /dev/null
+++ b/src/Rect.h
@@ -0,0 +1,94 @@
+/** @file Rect.h
+ @author Jukka Jylänki
+
+ This work is released to Public Domain, do whatever you want with it.
+*/
+#pragma once
+
+#include
+
+struct RectSize
+{
+ int width;
+ int height;
+};
+
+struct Rect
+{
+ int x;
+ int y;
+ int width;
+ int height;
+};
+
+/// Performs a lexicographic compare on (rect short side, rect long side).
+/// @return -1 if the smaller side of a is shorter than the smaller side of b, 1 if the other way around.
+/// If they are equal, the larger side length is used as a tie-breaker.
+/// If the rectangles are of same size, returns 0.
+int CompareRectShortSide(const Rect &a, const Rect &b);
+
+/// Performs a lexicographic compare on (x, y, width, height).
+int NodeSortCmp(const Rect &a, const Rect &b);
+
+/// Returns true if a is contained in b.
+bool IsContainedIn(const Rect &a, const Rect &b);
+
+#ifdef _DEBUG
+class DisjointRectCollection
+{
+public:
+ TArray rects;
+
+ bool Add(const Rect &r)
+ {
+ // Degenerate rectangles are ignored.
+ if (r.width == 0 || r.height == 0)
+ return true;
+
+ if (!Disjoint(r))
+ return false;
+ rects.Push(r);
+ return true;
+ }
+
+ bool Del(const Rect &r)
+ {
+ for(unsigned i = 0; i < rects.Size(); ++i)
+ {
+ if(r.x == rects[i].x && r.y == rects[i].y && r.width == rects[i].width && r.height == rects[i].height)
+ {
+ rects.Delete(i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void Clear()
+ {
+ rects.Clear();
+ }
+
+ bool Disjoint(const Rect &r) const
+ {
+ // Degenerate rectangles are ignored.
+ if (r.width == 0 || r.height == 0)
+ return true;
+
+ for(unsigned i = 0; i < rects.Size(); ++i)
+ if (!Disjoint(rects[i], r))
+ return false;
+ return true;
+ }
+
+ static bool Disjoint(const Rect &a, const Rect &b)
+ {
+ if (a.x + a.width <= b.x ||
+ b.x + b.width <= a.x ||
+ a.y + a.height <= b.y ||
+ b.y + b.height <= a.y)
+ return true;
+ return false;
+ }
+};
+#endif
diff --git a/src/SkylineBinPack.cpp b/src/SkylineBinPack.cpp
new file mode 100644
index 0000000000..cb0be54e13
--- /dev/null
+++ b/src/SkylineBinPack.cpp
@@ -0,0 +1,398 @@
+/** @file SkylineBinPack.cpp
+ @author Jukka Jylänki
+
+ @brief Implements different bin packer algorithms that use the SKYLINE data structure.
+
+ This work is released to Public Domain, do whatever you want with it.
+*/
+
+#include
+#include
+#include "templates.h"
+
+#include "SkylineBinPack.h"
+
+using namespace std;
+
+SkylineBinPack::SkylineBinPack()
+:binWidth(0),
+binHeight(0)
+{
+}
+
+SkylineBinPack::SkylineBinPack(int width, int height, bool useWasteMap)
+{
+ Init(width, height, useWasteMap);
+}
+
+void SkylineBinPack::Init(int width, int height, bool useWasteMap_)
+{
+ binWidth = width;
+ binHeight = height;
+
+ useWasteMap = useWasteMap_;
+
+#ifdef _DEBUG
+ disjointRects.Clear();
+#endif
+
+ usedSurfaceArea = 0;
+ skyLine.Clear();
+ SkylineNode node;
+ node.x = 0;
+ node.y = 0;
+ node.width = binWidth;
+ skyLine.Push(node);
+
+ if (useWasteMap)
+ {
+ wasteMap.Init(width, height);
+ wasteMap.GetFreeRectangles().Clear();
+ }
+}
+
+void SkylineBinPack::Insert(TArray &rects, TArray &dst)
+{
+ dst.Clear();
+
+ while(rects.Size() > 0)
+ {
+ Rect bestNode;
+ int bestScore1 = INT_MAX;
+ int bestScore2 = INT_MAX;
+ int bestSkylineIndex = -1;
+ int bestRectIndex = -1;
+ for(unsigned i = 0; i < rects.Size(); ++i)
+ {
+ Rect newNode;
+ int score1;
+ int score2;
+ int index;
+ newNode = FindPositionForNewNodeMinWaste(rects[i].width, rects[i].height, score2, score1, index);
+ assert(disjointRects.Disjoint(newNode));
+ if (newNode.height != 0)
+ {
+ if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2))
+ {
+ bestNode = newNode;
+ bestScore1 = score1;
+ bestScore2 = score2;
+ bestSkylineIndex = index;
+ bestRectIndex = i;
+ }
+ }
+ }
+
+ if (bestRectIndex == -1)
+ return;
+
+ // Perform the actual packing.
+ assert(disjointRects.Disjoint(bestNode));
+#ifdef _DEBUG
+ disjointRects.Add(bestNode);
+#endif
+ AddSkylineLevel(bestSkylineIndex, bestNode);
+ usedSurfaceArea += rects[bestRectIndex].width * rects[bestRectIndex].height;
+ rects.Delete(bestRectIndex);
+ dst.Push(bestNode);
+ }
+}
+
+Rect SkylineBinPack::Insert(int width, int height)
+{
+ // First try to pack this rectangle into the waste map, if it fits.
+ Rect node = wasteMap.Insert(width, height, true, GuillotineBinPack::RectBestShortSideFit,
+ GuillotineBinPack::SplitMaximizeArea);
+ assert(disjointRects.Disjoint(node));
+
+ if (node.height != 0)
+ {
+ Rect newNode;
+ newNode.x = node.x;
+ newNode.y = node.y;
+ newNode.width = node.width;
+ newNode.height = node.height;
+ usedSurfaceArea += width * height;
+ assert(disjointRects.Disjoint(newNode));
+#ifdef _DEBUG
+ disjointRects.Add(newNode);
+#endif
+ return newNode;
+ }
+
+ return InsertBottomLeft(width, height);
+}
+
+bool SkylineBinPack::RectangleFits(int skylineNodeIndex, int width, int height, int &y) const
+{
+ int x = skyLine[skylineNodeIndex].x;
+ if (x + width > binWidth)
+ return false;
+ int widthLeft = width;
+ int i = skylineNodeIndex;
+ y = skyLine[skylineNodeIndex].y;
+ while(widthLeft > 0)
+ {
+ y = MAX(y, skyLine[i].y);
+ if (y + height > binHeight)
+ return false;
+ widthLeft -= skyLine[i].width;
+ ++i;
+ assert(i < (int)skyLine.Size() || widthLeft <= 0);
+ }
+ return true;
+}
+
+int SkylineBinPack::ComputeWastedArea(int skylineNodeIndex, int width, int height, int y) const
+{
+ int wastedArea = 0;
+ const int rectLeft = skyLine[skylineNodeIndex].x;
+ const int rectRight = rectLeft + width;
+ for(; skylineNodeIndex < (int)skyLine.Size() && skyLine[skylineNodeIndex].x < rectRight; ++skylineNodeIndex)
+ {
+ if (skyLine[skylineNodeIndex].x >= rectRight || skyLine[skylineNodeIndex].x + skyLine[skylineNodeIndex].width <= rectLeft)
+ break;
+
+ int leftSide = skyLine[skylineNodeIndex].x;
+ int rightSide = MIN(rectRight, leftSide + skyLine[skylineNodeIndex].width);
+ assert(y >= skyLine[skylineNodeIndex].y);
+ wastedArea += (rightSide - leftSide) * (y - skyLine[skylineNodeIndex].y);
+ }
+ return wastedArea;
+}
+
+bool SkylineBinPack::RectangleFits(int skylineNodeIndex, int width, int height, int &y, int &wastedArea) const
+{
+ bool fits = RectangleFits(skylineNodeIndex, width, height, y);
+ if (fits)
+ wastedArea = ComputeWastedArea(skylineNodeIndex, width, height, y);
+
+ return fits;
+}
+
+void SkylineBinPack::AddWasteMapArea(int skylineNodeIndex, int width, int height, int y)
+{
+ int wastedArea = 0;
+ const int rectLeft = skyLine[skylineNodeIndex].x;
+ const int rectRight = rectLeft + width;
+ for(; skylineNodeIndex < (int)skyLine.Size() && skyLine[skylineNodeIndex].x < rectRight; ++skylineNodeIndex)
+ {
+ if (skyLine[skylineNodeIndex].x >= rectRight || skyLine[skylineNodeIndex].x + skyLine[skylineNodeIndex].width <= rectLeft)
+ break;
+
+ int leftSide = skyLine[skylineNodeIndex].x;
+ int rightSide = MIN(rectRight, leftSide + skyLine[skylineNodeIndex].width);
+ assert(y >= skyLine[skylineNodeIndex].y);
+
+ Rect waste;
+ waste.x = leftSide;
+ waste.y = skyLine[skylineNodeIndex].y;
+ waste.width = rightSide - leftSide;
+ waste.height = y - skyLine[skylineNodeIndex].y;
+
+ assert(disjointRects.Disjoint(waste));
+ wasteMap.GetFreeRectangles().Push(waste);
+ }
+}
+
+void SkylineBinPack::AddWaste(const Rect &waste)
+{
+ wasteMap.GetFreeRectangles().Push(waste);
+#ifdef _DEBUG
+ disjointRects.Del(waste);
+ wasteMap.DelDisjoint(waste);
+#endif
+}
+
+void SkylineBinPack::AddSkylineLevel(int skylineNodeIndex, const Rect &rect)
+{
+ // First track all wasted areas and mark them into the waste map if we're using one.
+ if (useWasteMap)
+ AddWasteMapArea(skylineNodeIndex, rect.width, rect.height, rect.y);
+
+ SkylineNode newNode;
+ newNode.x = rect.x;
+ newNode.y = rect.y + rect.height;
+ newNode.width = rect.width;
+ skyLine.Insert(skylineNodeIndex, newNode);
+
+ assert(newNode.x + newNode.width <= binWidth);
+ assert(newNode.y <= binHeight);
+
+ for(unsigned i = skylineNodeIndex+1; i < skyLine.Size(); ++i)
+ {
+ assert(skyLine[i-1].x <= skyLine[i].x);
+
+ if (skyLine[i].x < skyLine[i-1].x + skyLine[i-1].width)
+ {
+ int shrink = skyLine[i-1].x + skyLine[i-1].width - skyLine[i].x;
+
+ skyLine[i].x += shrink;
+ skyLine[i].width -= shrink;
+
+ if (skyLine[i].width <= 0)
+ {
+ skyLine.Delete(i);
+ --i;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ MergeSkylines();
+}
+
+void SkylineBinPack::MergeSkylines()
+{
+ for(unsigned i = 0; i < skyLine.Size()-1; ++i)
+ if (skyLine[i].y == skyLine[i+1].y)
+ {
+ skyLine[i].width += skyLine[i+1].width;
+ skyLine.Delete(i+1);
+ --i;
+ }
+}
+
+Rect SkylineBinPack::InsertBottomLeft(int width, int height)
+{
+ int bestHeight;
+ int bestWidth;
+ int bestIndex;
+ Rect newNode = FindPositionForNewNodeBottomLeft(width, height, bestHeight, bestWidth, bestIndex);
+
+ if (bestIndex != -1)
+ {
+ assert(disjointRects.Disjoint(newNode));
+ // Perform the actual packing.
+ AddSkylineLevel(bestIndex, newNode);
+
+ usedSurfaceArea += width * height;
+#ifdef _DEBUG
+ disjointRects.Add(newNode);
+#endif
+ }
+ else
+ memset(&newNode, 0, sizeof(Rect));
+
+ return newNode;
+}
+
+Rect SkylineBinPack::FindPositionForNewNodeBottomLeft(int width, int height, int &bestHeight, int &bestWidth, int &bestIndex) const
+{
+ bestHeight = INT_MAX;
+ bestIndex = -1;
+ // Used to break ties if there are nodes at the same level. Then pick the narrowest one.
+ bestWidth = INT_MAX;
+ Rect newNode = { 0, 0, 0, 0 };
+ for(unsigned i = 0; i < skyLine.Size(); ++i)
+ {
+ int y;
+ if (RectangleFits(i, width, height, y))
+ {
+ if (y + height < bestHeight || (y + height == bestHeight && skyLine[i].width < bestWidth))
+ {
+ bestHeight = y + height;
+ bestIndex = i;
+ bestWidth = skyLine[i].width;
+ newNode.x = skyLine[i].x;
+ newNode.y = y;
+ newNode.width = width;
+ newNode.height = height;
+ assert(disjointRects.Disjoint(newNode));
+ }
+ }
+/* if (RectangleFits(i, height, width, y))
+ {
+ if (y + width < bestHeight || (y + width == bestHeight && skyLine[i].width < bestWidth))
+ {
+ bestHeight = y + width;
+ bestIndex = i;
+ bestWidth = skyLine[i].width;
+ newNode.x = skyLine[i].x;
+ newNode.y = y;
+ newNode.width = height;
+ newNode.height = width;
+ assert(disjointRects.Disjoint(newNode));
+ }
+ }
+*/ }
+
+ return newNode;
+}
+
+Rect SkylineBinPack::InsertMinWaste(int width, int height)
+{
+ int bestHeight;
+ int bestWastedArea;
+ int bestIndex;
+ Rect newNode = FindPositionForNewNodeMinWaste(width, height, bestHeight, bestWastedArea, bestIndex);
+
+ if (bestIndex != -1)
+ {
+ assert(disjointRects.Disjoint(newNode));
+ // Perform the actual packing.
+ AddSkylineLevel(bestIndex, newNode);
+
+ usedSurfaceArea += width * height;
+#ifdef _DEBUG
+ disjointRects.Add(newNode);
+#endif
+ }
+ else
+ memset(&newNode, 0, sizeof(newNode));
+
+ return newNode;
+}
+
+Rect SkylineBinPack::FindPositionForNewNodeMinWaste(int width, int height, int &bestHeight, int &bestWastedArea, int &bestIndex) const
+{
+ bestHeight = INT_MAX;
+ bestWastedArea = INT_MAX;
+ bestIndex = -1;
+ Rect newNode;
+ memset(&newNode, 0, sizeof(newNode));
+ for(unsigned i = 0; i < skyLine.Size(); ++i)
+ {
+ int y;
+ int wastedArea;
+
+ if (RectangleFits(i, width, height, y, wastedArea))
+ {
+ if (wastedArea < bestWastedArea || (wastedArea == bestWastedArea && y + height < bestHeight))
+ {
+ bestHeight = y + height;
+ bestWastedArea = wastedArea;
+ bestIndex = i;
+ newNode.x = skyLine[i].x;
+ newNode.y = y;
+ newNode.width = width;
+ newNode.height = height;
+ assert(disjointRects.Disjoint(newNode));
+ }
+ }
+/* if (RectangleFits(i, height, width, y, wastedArea))
+ {
+ if (wastedArea < bestWastedArea || (wastedArea == bestWastedArea && y + width < bestHeight))
+ {
+ bestHeight = y + width;
+ bestWastedArea = wastedArea;
+ bestIndex = i;
+ newNode.x = skyLine[i].x;
+ newNode.y = y;
+ newNode.width = height;
+ newNode.height = width;
+ assert(disjointRects.Disjoint(newNode));
+ }
+ }*/
+ }
+
+ return newNode;
+}
+
+/// Computes the ratio of used surface area.
+float SkylineBinPack::Occupancy() const
+{
+ return (float)usedSurfaceArea / (binWidth * binHeight);
+}
diff --git a/src/SkylineBinPack.h b/src/SkylineBinPack.h
new file mode 100644
index 0000000000..937c88de60
--- /dev/null
+++ b/src/SkylineBinPack.h
@@ -0,0 +1,91 @@
+/** @file SkylineBinPack.h
+ @author Jukka Jylänki
+
+ @brief Implements different bin packer algorithms that use the SKYLINE data structure.
+
+ This work is released to Public Domain, do whatever you want with it.
+*/
+#pragma once
+
+#include "tarray.h"
+
+#include "Rect.h"
+#include "GuillotineBinPack.h"
+
+/** Implements bin packing algorithms that use the SKYLINE data structure to store the bin contents. Uses
+ GuillotineBinPack as the waste map. */
+class SkylineBinPack
+{
+public:
+ /// Instantiates a bin of size (0,0). Call Init to create a new bin.
+ SkylineBinPack();
+
+ /// Instantiates a bin of the given size.
+ SkylineBinPack(int binWidth, int binHeight, bool useWasteMap);
+
+ /// (Re)initializes the packer to an empty bin of width x height units. Call whenever
+ /// you need to restart with a new bin.
+ void Init(int binWidth, int binHeight, bool useWasteMap);
+
+ /// Inserts the given list of rectangles in an offline/batch mode, possibly rotated.
+ /// @param rects The list of rectangles to insert. This vector will be destroyed in the process.
+ /// @param dst [out] This list will contain the packed rectangles. The indices will not correspond to that of rects.
+ /// @param method The rectangle placement rule to use when packing.
+ void Insert(TArray &rects, TArray &dst);
+
+ /// Inserts a single rectangle into the bin, possibly rotated.
+ Rect Insert(int width, int height);
+
+ /// Adds a rectangle to the waste list. It must have been previously returned by
+ /// Insert or the results are undefined.
+ void AddWaste(const Rect &rect);
+
+ /// Computes the ratio of used surface area to the total bin area.
+ float Occupancy() const;
+
+private:
+ int binWidth;
+ int binHeight;
+
+#ifdef _DEBUG
+ DisjointRectCollection disjointRects;
+#endif
+
+ /// Represents a single level (a horizontal line) of the skyline/horizon/envelope.
+ struct SkylineNode
+ {
+ /// The starting x-coordinate (leftmost).
+ int x;
+
+ /// The y-coordinate of the skyline level line.
+ int y;
+
+ /// The line width. The ending coordinate (inclusive) will be x+width-1.
+ int width;
+ };
+
+ TArray skyLine;
+
+ unsigned long usedSurfaceArea;
+
+ /// If true, we use the GuillotineBinPack structure to recover wasted areas into a waste map.
+ bool useWasteMap;
+ GuillotineBinPack wasteMap;
+
+ Rect InsertBottomLeft(int width, int height);
+ Rect InsertMinWaste(int width, int height);
+
+ Rect FindPositionForNewNodeBottomLeft(int width, int height, int &bestHeight, int &bestWidth, int &bestIndex) const;
+ Rect FindPositionForNewNodeMinWaste(int width, int height, int &bestHeight, int &bestWastedArea, int &bestIndex) const;
+
+ bool RectangleFits(int skylineNodeIndex, int width, int height, int &y) const;
+ bool RectangleFits(int skylineNodeIndex, int width, int height, int &y, int &wastedArea) const;
+ int ComputeWastedArea(int skylineNodeIndex, int width, int height, int y) const;
+
+ void AddWasteMapArea(int skylineNodeIndex, int width, int height, int y);
+
+ void AddSkylineLevel(int skylineNodeIndex, const Rect &rect);
+
+ /// Merges all skyline nodes that are at the same level.
+ void MergeSkylines();
+};
diff --git a/src/actor.h b/src/actor.h
index 0f85afa76b..0e22bc2898 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -569,6 +569,36 @@ struct line_t;
struct secplane_t;
struct FStrifeDialogueNode;
+struct fixedvec3
+{
+ fixed_t x, y, z;
+
+ operator FVector3()
+ {
+ return FVector3(FIXED2FLOAT(x), FIXED2FLOAT(y), FIXED2FLOAT(z));
+ }
+
+ operator TVector3()
+ {
+ return TVector3(FIXED2DBL(x), FIXED2DBL(y), FIXED2DBL(z));
+ }
+};
+
+struct fixedvec2
+{
+ fixed_t x, y;
+
+ operator FVector2()
+ {
+ return FVector2(FIXED2FLOAT(x), FIXED2FLOAT(y));
+ }
+
+ operator TVector2()
+ {
+ return TVector2(FIXED2DBL(x), FIXED2DBL(y));
+ }
+};
+
class DDropItem : public DObject
{
DECLARE_CLASS(DDropItem, DObject)
@@ -580,6 +610,10 @@ public:
int Amount;
};
+fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); // since we cannot include p_local here...
+angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); // same reason here with r_defs.h
+
+
// Map Object definition.
class AActor : public DThinker
{
@@ -823,6 +857,90 @@ public:
return bloodcls;
}
+ // 'absolute' is reserved for a linked portal implementation which needs
+ // to distinguish between portal-aware and portal-unaware distance calculation.
+ fixed_t AproxDistance(AActor *other, bool absolute = false)
+ {
+ return P_AproxDistance(x - other->x, y - other->y);
+ }
+
+ // same with 'ref' here.
+ fixed_t AproxDistance(fixed_t otherx, fixed_t othery, AActor *ref = NULL)
+ {
+ return P_AproxDistance(x - otherx, y - othery);
+ }
+
+ fixed_t AproxDistance(AActor *other, fixed_t xadd, fixed_t yadd, bool absolute = false)
+ {
+ return P_AproxDistance(x - other->x + xadd, y - other->y + yadd);
+ }
+
+ fixed_t AproxDistance3D(AActor *other, bool absolute = false)
+ {
+ return P_AproxDistance(AproxDistance(other), z - other->z);
+ }
+
+ // more precise, but slower version, being used in a few places
+ fixed_t Distance2D(AActor *other, bool absolute = false)
+ {
+ return xs_RoundToInt(FVector2(x - other->x, y - other->y).Length());
+ }
+
+ // a full 3D version of the above
+ fixed_t Distance3D(AActor *other, bool absolute = false)
+ {
+ return xs_RoundToInt(FVector3(x - other->x, y - other->y, z - other->z).Length());
+ }
+
+ angle_t AngleTo(AActor *other, bool absolute = false) const
+ {
+ return R_PointToAngle2(x, y, other->x, other->y);
+ }
+
+ angle_t AngleTo(AActor *other, fixed_t oxofs, fixed_t oyofs, bool absolute = false) const
+ {
+ return R_PointToAngle2(x, y, other->x + oxofs, other->y + oyofs);
+ }
+
+ fixed_t AngleTo(fixed_t otherx, fixed_t othery, AActor *ref = NULL)
+ {
+ return R_PointToAngle2(x, y, otherx, othery);
+ }
+
+ fixed_t AngleXYTo(fixed_t myx, fixed_t myy, AActor *other, bool absolute = false)
+ {
+ return R_PointToAngle2(myx, myy, other->x, other->y);
+ }
+
+ fixedvec2 Vec2To(AActor *other) const
+ {
+ fixedvec2 ret = { other->x - x, other->y - y };
+ return ret;
+ }
+
+ fixedvec3 Vec3To(AActor *other) const
+ {
+ fixedvec3 ret = { other->x - x, other->y - y, other->z - z };
+ return ret;
+ }
+
+ fixedvec2 Vec2Offset(fixed_t dx, fixed_t dy) const
+ {
+ fixedvec2 ret = { x + dx, y + dy };
+ return ret;
+ }
+
+ fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz) const
+ {
+ fixedvec3 ret = { x + dx, y + dy, z + dz };
+ return ret;
+ }
+
+ void Move(fixed_t dx, fixed_t dy, fixed_t dz)
+ {
+ SetOrigin(x + dx, y + dy, z + dz, true);
+ }
+
inline void SetFriendPlayer(player_t *player);
bool IsVisibleToPlayer() const;
@@ -866,6 +984,7 @@ public:
struct sector_t *floorsector;
FTextureID floorpic; // contacted sec floorpic
+ int floorterrain;
struct sector_t *ceilingsector;
FTextureID ceilingpic; // contacted sec ceilingpic
fixed_t radius, height; // for movement checking
@@ -1039,7 +1158,7 @@ public:
void LinkToWorld (sector_t *sector);
void UnlinkFromWorld ();
void AdjustFloorClip ();
- void SetOrigin (fixed_t x, fixed_t y, fixed_t z);
+ void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving = false);
bool InStateSequence(FState * newstate, FState * basestate);
int GetTics(FState * newstate);
bool SetState (FState *newstate, bool nofunction=false);
@@ -1068,6 +1187,24 @@ public:
}
bool HasSpecialDeathStates () const;
+
+ fixed_t X() const
+ {
+ return x;
+ }
+ fixed_t Y() const
+ {
+ return y;
+ }
+ fixed_t Z() const
+ {
+ return z;
+ }
+ void SetZ(fixed_t newz)
+ {
+ z = newz;
+ }
+
};
class FActorIterator
@@ -1140,15 +1277,36 @@ inline AActor *Spawn (PClassActor *type, fixed_t x, fixed_t y, fixed_t z, replac
{
return AActor::StaticSpawn (type, x, y, z, allowreplacement);
}
+inline AActor *Spawn (PClassActor *type, const fixedvec3 &pos, replace_t allowreplacement)
+{
+ return AActor::StaticSpawn (type, pos.x, pos.y, pos.z, allowreplacement);
+}
+
AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement);
AActor *Spawn (FName classname, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement);
+inline AActor *Spawn (const char *type, const fixedvec3 &pos, replace_t allowreplacement)
+{
+ return Spawn (type, pos.x, pos.y, pos.z, allowreplacement);
+}
+
+inline AActor *Spawn (FName classname, const fixedvec3 &pos, replace_t allowreplacement)
+{
+ return Spawn (classname, pos.x, pos.y, pos.z, allowreplacement);
+}
+
+
template
inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement)
{
return static_cast(AActor::StaticSpawn (RUNTIME_TEMPLATE_CLASS(T), x, y, z, allowreplacement));
}
+template
+inline T *Spawn (const fixedvec3 &pos, replace_t allowreplacement)
+{
+ return static_cast(AActor::StaticSpawn (RUNTIME_CLASS(T), pos.x, pos.y, pos.z, allowreplacement));
+}
void PrintMiscActorInfo(AActor * query);
diff --git a/src/am_map.cpp b/src/am_map.cpp
index 81e45c6858..64d5420b0c 100644
--- a/src/am_map.cpp
+++ b/src/am_map.cpp
@@ -998,8 +998,8 @@ void AM_restoreScaleAndLoc ()
}
else
{
- m_x = (players[consoleplayer].camera->x >> FRACTOMAPBITS) - m_w/2;
- m_y = (players[consoleplayer].camera->y >> FRACTOMAPBITS)- m_h/2;
+ m_x = (players[consoleplayer].camera->X() >> FRACTOMAPBITS) - m_w/2;
+ m_y = (players[consoleplayer].camera->Y() >> FRACTOMAPBITS)- m_h/2;
}
m_x2 = m_x + m_w;
m_y2 = m_y + m_h;
@@ -1249,8 +1249,8 @@ void AM_initVariables ()
if (playeringame[pnum])
break;
assert(pnum >= 0 && pnum < MAXPLAYERS);
- m_x = (players[pnum].camera->x >> FRACTOMAPBITS) - m_w/2;
- m_y = (players[pnum].camera->y >> FRACTOMAPBITS) - m_h/2;
+ m_x = (players[pnum].camera->X() >> FRACTOMAPBITS) - m_w/2;
+ m_y = (players[pnum].camera->Y() >> FRACTOMAPBITS) - m_h/2;
AM_changeWindowLoc();
// for saving & restoring
@@ -1571,25 +1571,25 @@ void AM_doFollowPlayer ()
fixed_t sx, sy;
if (players[consoleplayer].camera != NULL &&
- (f_oldloc.x != players[consoleplayer].camera->x ||
- f_oldloc.y != players[consoleplayer].camera->y))
+ (f_oldloc.x != players[consoleplayer].camera->X() ||
+ f_oldloc.y != players[consoleplayer].camera->Y()))
{
- m_x = (players[consoleplayer].camera->x >> FRACTOMAPBITS) - m_w/2;
- m_y = (players[consoleplayer].camera->y >> FRACTOMAPBITS) - m_h/2;
+ m_x = (players[consoleplayer].camera->X() >> FRACTOMAPBITS) - m_w/2;
+ m_y = (players[consoleplayer].camera->Y() >> FRACTOMAPBITS) - m_h/2;
m_x2 = m_x + m_w;
m_y2 = m_y + m_h;
// do the parallax parchment scrolling.
- sx = (players[consoleplayer].camera->x - f_oldloc.x) >> FRACTOMAPBITS;
- sy = (f_oldloc.y - players[consoleplayer].camera->y) >> FRACTOMAPBITS;
+ sx = (players[consoleplayer].camera->X() - f_oldloc.x) >> FRACTOMAPBITS;
+ sy = (f_oldloc.y - players[consoleplayer].camera->Y()) >> FRACTOMAPBITS;
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
{
AM_rotate (&sx, &sy, players[consoleplayer].camera->angle - ANG90);
}
AM_ScrollParchment (sx, sy);
- f_oldloc.x = players[consoleplayer].camera->x;
- f_oldloc.y = players[consoleplayer].camera->y;
+ f_oldloc.x = players[consoleplayer].camera->X();
+ f_oldloc.y = players[consoleplayer].camera->Y();
}
}
@@ -2071,17 +2071,17 @@ static bool AM_CheckSecret(line_t *line)
{
if (line->frontsector != NULL)
{
- if (line->frontsector->secretsector)
+ if (line->frontsector->wasSecret())
{
- if (am_map_secrets!=0 && !(line->frontsector->special&SECRET_MASK)) return true;
+ if (am_map_secrets!=0 && !line->frontsector->isSecret()) return true;
if (am_map_secrets==2 && !(line->flags & ML_SECRET)) return true;
}
}
if (line->backsector != NULL)
{
- if (line->backsector->secretsector)
+ if (line->backsector->wasSecret())
{
- if (am_map_secrets!=0 && !(line->backsector->special&SECRET_MASK)) return true;
+ if (am_map_secrets!=0 && !line->backsector->isSecret()) return true;
if (am_map_secrets==2 && !(line->flags & ML_SECRET)) return true;
}
}
@@ -2612,8 +2612,8 @@ void AM_drawPlayers ()
mline_t *arrow;
int numarrowlines;
- pt.x = players[consoleplayer].camera->x >> FRACTOMAPBITS;
- pt.y = players[consoleplayer].camera->y >> FRACTOMAPBITS;
+ pt.x = players[consoleplayer].camera->X() >> FRACTOMAPBITS;
+ pt.y = players[consoleplayer].camera->Y() >> FRACTOMAPBITS;
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
{
angle = ANG90;
@@ -2675,8 +2675,8 @@ void AM_drawPlayers ()
if (p->mo != NULL)
{
- pt.x = p->mo->x >> FRACTOMAPBITS;
- pt.y = p->mo->y >> FRACTOMAPBITS;
+ pt.x = p->mo->X() >> FRACTOMAPBITS;
+ pt.y = p->mo->Y() >> FRACTOMAPBITS;
angle = p->mo->angle;
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
@@ -2707,8 +2707,8 @@ void AM_drawKeys ()
while ((key = it.Next()) != NULL)
{
- p.x = key->x >> FRACTOMAPBITS;
- p.y = key->y >> FRACTOMAPBITS;
+ p.x = key->X() >> FRACTOMAPBITS;
+ p.y = key->Y() >> FRACTOMAPBITS;
angle = key->angle;
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
@@ -2752,8 +2752,8 @@ void AM_drawThings ()
{
if (am_cheat > 0 || !(t->flags6 & MF6_NOTONAUTOMAP))
{
- p.x = t->x >> FRACTOMAPBITS;
- p.y = t->y >> FRACTOMAPBITS;
+ p.x = t->X() >> FRACTOMAPBITS;
+ p.y = t->Y() >> FRACTOMAPBITS;
if (am_showthingsprites > 0 && t->sprite > 0)
{
@@ -2979,7 +2979,7 @@ void AM_drawAuthorMarkers ()
marked->subsector->flags & SSECF_DRAWN :
marked->Sector->MoreFlags & SECF_DRAWN)))
{
- DrawMarker (tex, marked->x >> FRACTOMAPBITS, marked->y >> FRACTOMAPBITS, 0,
+ DrawMarker (tex, marked->X() >> FRACTOMAPBITS, marked->Y() >> FRACTOMAPBITS, 0,
flip, mark->scaleX, mark->scaleY, mark->Translation,
mark->alpha, mark->fillcolor, mark->RenderStyle);
}
diff --git a/src/b_func.cpp b/src/b_func.cpp
index f93625612f..cc8d9808a6 100644
--- a/src/b_func.cpp
+++ b/src/b_func.cpp
@@ -30,17 +30,17 @@ bool DBot::Reachable (AActor *rtarget)
if (player->mo == rtarget)
return false;
- if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget->x, rtarget->y) -
- rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y))
+ if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget) -
+ rtarget->Sector->floorplane.ZatPoint (rtarget))
< player->mo->height) //Where rtarget is, player->mo can't be.
return false;
sector_t *last_s = player->mo->Sector;
- fixed_t last_z = last_s->floorplane.ZatPoint (player->mo->x, player->mo->y);
- fixed_t estimated_dist = P_AproxDistance (player->mo->x - rtarget->x, player->mo->y - rtarget->y);
+ fixed_t last_z = last_s->floorplane.ZatPoint (player->mo);
+ fixed_t estimated_dist = player->mo->AproxDistance(rtarget);
bool reachable = true;
- FPathTraverse it(player->mo->x+player->mo->velx, player->mo->y+player->mo->vely, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS);
+ FPathTraverse it(player->mo->X()+player->mo->velx, player->mo->Y()+player->mo->vely, rtarget->X(), rtarget->Y(), PT_ADDLINES|PT_ADDTHINGS);
intercept_t *in;
while ((in = it.Next()))
{
@@ -96,7 +96,7 @@ bool DBot::Reachable (AActor *rtarget)
thing = in->d.thing;
if (thing == player->mo) //Can't reach self in this case.
continue;
- if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT)))
+ if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget) <= (last_z+MAXMOVEHEIGHT)))
{
return true;
}
@@ -123,7 +123,7 @@ bool DBot::Check_LOS (AActor *to, angle_t vangle)
if (vangle == 0)
return false; //Looker seems to be blind.
- return absangle(R_PointToAngle2 (player->mo->x, player->mo->y, to->x, to->y) - player->mo->angle) <= vangle/2;
+ return absangle(player->mo->AngleTo(to) - player->mo->angle) <= vangle/2;
}
//-------------------------------------
@@ -165,10 +165,8 @@ void DBot::Dofire (ticcmd_t *cmd)
//MAKEME: Decrease the rocket suicides even more.
no_fire = true;
- //angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y);
//Distance to enemy.
- dist = P_AproxDistance ((player->mo->x + player->mo->velx) - (enemy->x + enemy->velx),
- (player->mo->y + player->mo->vely) - (enemy->y + enemy->vely));
+ dist = player->mo->AproxDistance(enemy, player->mo->velx - enemy->velx, player->mo->vely - enemy->vely);
//FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go.
if (player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON)
@@ -219,17 +217,17 @@ void DBot::Dofire (ticcmd_t *cmd)
}
// prediction aiming
shootmissile:
- dist = P_AproxDistance (player->mo->x - enemy->x, player->mo->y - enemy->y);
+ dist = player->mo->AproxDistance (enemy);
m = dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed;
- bglobal.SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1);
- angle = R_PointToAngle2 (player->mo->x, player->mo->y, bglobal.body1->x, bglobal.body1->y);
+ bglobal.SetBodyAt (enemy->X() + enemy->velx*m*2, enemy->Y() + enemy->vely*m*2, enemy->Z(), 1);
+ angle = player->mo->AngleTo(bglobal.body1);
if (Check_LOS (enemy, SHOOTFOV))
no_fire = false;
}
else
{
//Other weapons, mostly instant hit stuff.
- angle = R_PointToAngle2 (player->mo->x, player->mo->y, enemy->x, enemy->y);
+ angle = player->mo->AngleTo(enemy);
aiming_penalty = 0;
if (enemy->flags & MF_SHADOW)
aiming_penalty += (pr_botdofire()%25)+10;
@@ -265,7 +263,6 @@ shootmissile:
cmd->ucmd.buttons |= BT_ATTACK;
}
//Prevents bot from jerking, when firing automatic things with low skill.
- //player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y);
}
bool FCajunMaster::IsLeader (player_t *player)
@@ -331,8 +328,7 @@ AActor *DBot::Choose_Mate ()
{
if (P_CheckSight (player->mo, client->mo, SF_IGNOREVISIBILITY))
{
- test = P_AproxDistance (client->mo->x - player->mo->x,
- client->mo->y - player->mo->y);
+ test = client->mo->AproxDistance(player->mo);
if (test < closest_dist)
{
@@ -402,8 +398,7 @@ AActor *DBot::Find_enemy ()
if (Check_LOS (client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up.
//if(P_CheckSight(player->mo, players[count].mo))
{
- temp = P_AproxDistance (client->mo->x - player->mo->x,
- client->mo->y - player->mo->y);
+ temp = client->mo->AproxDistance(player->mo);
//Too dark?
if (temp > DARK_DIST &&
@@ -432,7 +427,7 @@ void FCajunMaster::SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum)
{
if (body1)
{
- body1->SetOrigin (x, y, z);
+ body1->SetOrigin (x, y, z, false);
}
else
{
@@ -443,7 +438,7 @@ void FCajunMaster::SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum)
{
if (body2)
{
- body2->SetOrigin (x, y, z);
+ body2->SetOrigin (x, y, z, false);
}
else
{
@@ -464,16 +459,13 @@ void FCajunMaster::SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum)
//Emulates missile travel. Returns distance travelled.
fixed_t FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd)
{
- AActor *th = Spawn ("CajunTrace", source->x, source->y, source->z + 4*8*FRACUNIT, NO_REPLACE);
+ AActor *th = Spawn ("CajunTrace", source->X(), source->Y(), source->Z() + 4*8*FRACUNIT, NO_REPLACE);
th->target = source; // where it came from
float speed = (float)th->Speed;
- FVector3 velocity;
- velocity[0] = FIXED2FLOAT(dest->x - source->x);
- velocity[1] = FIXED2FLOAT(dest->y - source->y);
- velocity[2] = FIXED2FLOAT(dest->z - source->z);
+ TVector3 velocity = source->Vec3To(dest);
velocity.MakeUnit();
th->velx = FLOAT2FIXED(velocity[0] * speed);
th->vely = FLOAT2FIXED(velocity[1] * speed);
@@ -484,8 +476,8 @@ fixed_t FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd)
while (dist < SAFE_SELF_MISDIST)
{
dist += th->Speed;
- th->SetOrigin (th->x + th->velx, th->y + th->vely, th->z + th->velz);
- if (!CleanAhead (th, th->x, th->y, cmd))
+ th->Move(th->velx, th->vely, th->velz);
+ if (!CleanAhead (th, th->X(), th->Y(), cmd))
break;
}
th->Destroy ();
@@ -499,30 +491,30 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd)
AActor *actor;
int m;
- bglobal.SetBodyAt (player->mo->x + FixedMul(player->mo->velx, 5*FRACUNIT),
- player->mo->y + FixedMul(player->mo->vely, 5*FRACUNIT),
- player->mo->z + (player->mo->height / 2), 2);
+ bglobal.SetBodyAt (player->mo->X() + FixedMul(player->mo->velx, 5*FRACUNIT),
+ player->mo->Y() + FixedMul(player->mo->vely, 5*FRACUNIT),
+ player->mo->Z() + (player->mo->height / 2), 2);
actor = bglobal.body2;
- dist = P_AproxDistance (actor->x-enemy->x, actor->y-enemy->y);
+ dist = actor->AproxDistance (enemy);
if (dist < SAFE_SELF_MISDIST)
return 0;
//Predict.
m = (((dist+1)/FRACUNIT) / GetDefaultByName("Rocket")->Speed);
- bglobal.SetBodyAt (enemy->x + FixedMul(enemy->velx, (m+2*FRACUNIT)),
- enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1);
+ bglobal.SetBodyAt (enemy->X() + FixedMul(enemy->velx, (m+2*FRACUNIT)),
+ enemy->Y() + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1);
//try the predicted location
if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile
{
FCheckPosition tm;
- if (bglobal.SafeCheckPosition (player->mo, actor->x, actor->y, tm))
+ if (bglobal.SafeCheckPosition (player->mo, actor->X(), actor->Y(), tm))
{
if (bglobal.FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST)
{
- ang = R_PointToAngle2 (actor->x, actor->y, bglobal.body1->x, bglobal.body1->y);
+ ang = actor->AngleTo(bglobal.body1);
return ang;
}
}
@@ -532,7 +524,7 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd)
{
if (bglobal.FakeFire (player->mo, enemy, cmd) >= SAFE_SELF_MISDIST)
{
- ang = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y);
+ ang = player->mo->AngleTo(enemy);
return ang;
}
}
diff --git a/src/b_game.cpp b/src/b_game.cpp
index e136f3f29b..5f852d043d 100644
--- a/src/b_game.cpp
+++ b/src/b_game.cpp
@@ -423,8 +423,8 @@ void FCajunMaster::RemoveAllBots (bool fromlist)
}
}
}
+ FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, players[i].mo, true, i, true);
ClearPlayer (i, !fromlist);
- FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, NULL, true, i);
}
}
diff --git a/src/b_move.cpp b/src/b_move.cpp
index fd04054577..cee409265e 100644
--- a/src/b_move.cpp
+++ b/src/b_move.cpp
@@ -35,7 +35,7 @@ void DBot::Roam (ticcmd_t *cmd)
if (Reachable(dest))
{ // Straight towards it.
- angle = R_PointToAngle2(player->mo->x, player->mo->y, dest->x, dest->y);
+ angle = player->mo->AngleTo(dest);
}
else if (player->mo->movedir < 8) // turn towards movement direction if not there yet
{
@@ -67,8 +67,8 @@ bool DBot::Move (ticcmd_t *cmd)
if ((unsigned)player->mo->movedir >= 8)
I_Error ("Weird bot movedir!");
- tryx = player->mo->x + 8*xspeed[player->mo->movedir];
- tryy = player->mo->y + 8*yspeed[player->mo->movedir];
+ tryx = player->mo->X() + 8*xspeed[player->mo->movedir];
+ tryy = player->mo->Y() + 8*yspeed[player->mo->movedir];
try_ok = bglobal.CleanAhead (player->mo, tryx, tryy, cmd);
@@ -124,9 +124,6 @@ bool DBot::TryWalk (ticcmd_t *cmd)
void DBot::NewChaseDir (ticcmd_t *cmd)
{
- fixed_t deltax;
- fixed_t deltay;
-
dirtype_t d[3];
int tdir;
@@ -145,19 +142,18 @@ void DBot::NewChaseDir (ticcmd_t *cmd)
olddir = (dirtype_t)player->mo->movedir;
turnaround = opposite[olddir];
- deltax = dest->x - player->mo->x;
- deltay = dest->y - player->mo->y;
+ fixedvec2 delta = player->mo->Vec2To(dest);
- if (deltax > 10*FRACUNIT)
+ if (delta.x > 10*FRACUNIT)
d[1] = DI_EAST;
- else if (deltax < -10*FRACUNIT)
+ else if (delta.x < -10*FRACUNIT)
d[1] = DI_WEST;
else
d[1] = DI_NODIR;
- if (deltay < -10*FRACUNIT)
+ if (delta.y < -10*FRACUNIT)
d[2] = DI_SOUTH;
- else if (deltay > 10*FRACUNIT)
+ else if (delta.y > 10*FRACUNIT)
d[2] = DI_NORTH;
else
d[2] = DI_NODIR;
@@ -165,14 +161,14 @@ void DBot::NewChaseDir (ticcmd_t *cmd)
// try direct route
if (d[1] != DI_NODIR && d[2] != DI_NODIR)
{
- player->mo->movedir = diags[((deltay<0)<<1)+(deltax>0)];
+ player->mo->movedir = diags[((delta.y<0)<<1)+(delta.x>0)];
if (player->mo->movedir != turnaround && TryWalk(cmd))
return;
}
// try other directions
if (pr_botnewchasedir() > 200
- || abs(deltay)>abs(deltax))
+ || abs(delta.y)>abs(delta.x))
{
tdir=d[1];
d[1]=d[2];
@@ -282,7 +278,7 @@ bool FCajunMaster::CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cm
if ( !(thing->flags & MF_TELEPORT) &&
- tm.ceilingz - thing->z < thing->height)
+ tm.ceilingz - thing->Z() < thing->height)
return false; // mobj must lower itself to fit
// jump out of water
@@ -290,7 +286,7 @@ bool FCajunMaster::CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cm
// maxstep=37*FRACUNIT;
if ( !(thing->flags & MF_TELEPORT) &&
- (tm.floorz - thing->z > maxstep ) )
+ (tm.floorz - thing->Z() > maxstep ) )
return false; // too big a step up
@@ -346,28 +342,13 @@ void DBot::Pitch (AActor *target)
double aim;
double diff;
- diff = target->z - player->mo->z;
- aim = atan (diff / (double)P_AproxDistance (player->mo->x - target->x, player->mo->y - target->y));
+ diff = target->Z() - player->mo->Z();
+ aim = atan(diff / (double)player->mo->AproxDistance(target));
player->mo->pitch = -(int)(aim * ANGLE_180/M_PI);
}
//Checks if a sector is dangerous.
bool FCajunMaster::IsDangerous (sector_t *sec)
{
- int special;
-
- return
- sec->damage
- || sec->special & DAMAGE_MASK
- || (special = sec->special & 0xff, special == dLight_Strobe_Hurt)
- || special == dDamage_Hellslime
- || special == dDamage_Nukage
- || special == dDamage_End
- || special == dDamage_SuperHellslime
- || special == dDamage_LavaWimpy
- || special == dDamage_LavaHefty
- || special == dScroll_EastLavaDamage
- || special == sLight_Strobe_Hurt
- || special == Damage_InstantDeath
- || special == sDamage_SuperHellslime;
+ return sec->damageamount > 0;
}
diff --git a/src/b_think.cpp b/src/b_think.cpp
index ea65395d6b..a2b169f56d 100644
--- a/src/b_think.cpp
+++ b/src/b_think.cpp
@@ -81,7 +81,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd)
int r;
stuck = false;
- dist = dest ? P_AproxDistance(player->mo->x-dest->x, player->mo->y-dest->y) : 0;
+ dist = dest ? player->mo->AproxDistance(dest) : 0;
if (missile &&
((!missile->velx || !missile->vely) || !Check_LOS(missile, SHOOTFOV*3/2)))
@@ -96,14 +96,14 @@ void DBot::ThinkForMove (ticcmd_t *cmd)
player->mo->pitch += 80;
//HOW TO MOVE:
- if (missile && (P_AproxDistance(player->mo->x-missile->x, player->mo->y-missile->y)mo->AproxDistance(missile)mo->x, player->mo->y, missile->x, missile->y);
+ angle = player->mo->AngleTo(missile);
cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN;
cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best.
- if ((P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000)
+ if ((player->mo->AproxDistance(oldx, oldy)<50000)
&& t_strafe<=0)
{
t_strafe = 5;
@@ -156,7 +156,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd)
t_fight = AFTERTICS;
if (t_strafe <= 0 &&
- (P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000
+ (player->mo->AproxDistance(oldx, oldy)<50000
|| ((pr_botmove()%30)==10))
)
{
@@ -165,10 +165,10 @@ void DBot::ThinkForMove (ticcmd_t *cmd)
sleft = !sleft;
}
- angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y);
+ angle = player->mo->AngleTo(enemy);
if (player->ReadyWeapon == NULL ||
- P_AproxDistance(player->mo->x-enemy->x, player->mo->y-enemy->y) >
+ player->mo->AproxDistance(enemy) >
player->ReadyWeapon->MoveCombatDist)
{
// If a monster, use lower speed (just for cooler apperance while strafing down doomed monster)
@@ -206,9 +206,9 @@ void DBot::ThinkForMove (ticcmd_t *cmd)
goto roam;
}
- angle = R_PointToAngle2(player->mo->x, player->mo->y, mate->x, mate->y);
+ angle = player->mo->AngleTo(mate);
- matedist = P_AproxDistance(player->mo->x - mate->x, player->mo->y - mate->y);
+ matedist = player->mo->AproxDistance(mate);
if (matedist > (FRIEND_DIST*2))
cmd->ucmd.forwardmove = FORWARDRUN;
else if (matedist > FRIEND_DIST)
@@ -241,7 +241,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd)
(pr_botmove()%100)>skill.isp) && player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
dest = enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy.
else //hide while t_fight, but keep view at enemy.
- angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y);
+ angle = player->mo->AngleTo(enemy);
} //Just a monster, so kill it.
else
dest = enemy;
@@ -303,8 +303,8 @@ void DBot::ThinkForMove (ticcmd_t *cmd)
if (t_fight<(AFTERTICS/2))
player->mo->flags |= MF_DROPOFF;
- oldx = player->mo->x;
- oldy = player->mo->y;
+ oldx = player->mo->X();
+ oldy = player->mo->Y();
}
//BOT_WhatToGet
diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp
index 803f2eae43..485a09f517 100644
--- a/src/c_cmds.cpp
+++ b/src/c_cmds.cpp
@@ -942,7 +942,7 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha
{
Printf ("%s at (%d,%d,%d)\n",
mo->GetClass()->TypeName.GetChars(),
- mo->x >> FRACBITS, mo->y >> FRACBITS, mo->z >> FRACBITS);
+ mo->X() >> FRACBITS, mo->Y() >> FRACBITS, mo->Z() >> FRACBITS);
}
}
}
@@ -1082,7 +1082,7 @@ CCMD(currentpos)
{
AActor *mo = players[consoleplayer].mo;
Printf("Current player position: (%1.3f,%1.3f,%1.3f), angle: %1.3f, floorheight: %1.3f, sector:%d, lightlevel: %d\n",
- FIXED2FLOAT(mo->x), FIXED2FLOAT(mo->y), FIXED2FLOAT(mo->z), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel);
+ FIXED2FLOAT(mo->X()), FIXED2FLOAT(mo->Y()), FIXED2FLOAT(mo->Z()), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel);
}
//-----------------------------------------------------------------------------
@@ -1132,11 +1132,8 @@ static void PrintSecretString(const char *string, bool thislevel)
if (*string == ';') string++;
if (thislevel && secnum >= 0 && secnum < numsectors)
{
- if (sectors[secnum].secretsector)
- {
- if ((sectors[secnum].special & SECRET_MASK)) colstr = TEXTCOLOR_RED;
- else colstr = TEXTCOLOR_GREEN;
- }
+ if (sectors[secnum].isSecret()) colstr = TEXTCOLOR_RED;
+ else if (sectors[secnum].wasSecret()) colstr = TEXTCOLOR_GREEN;
else colstr = TEXTCOLOR_ORANGE;
}
}
diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp
index 72c5bd0ff3..a20b298e56 100644
--- a/src/d_dehacked.cpp
+++ b/src/d_dehacked.cpp
@@ -3091,7 +3091,7 @@ bool ADehackedPickup::TryPickup (AActor *&toucher)
{
return false;
}
- RealPickup = static_cast(Spawn (type, x, y, z, NO_REPLACE));
+ RealPickup = static_cast(Spawn (type, X(), Y(), Z(), NO_REPLACE));
if (RealPickup != NULL)
{
// The internally spawned item should never count towards statistics.
diff --git a/src/d_net.cpp b/src/d_net.cpp
index 68368c01b1..791ce18a1a 100644
--- a/src/d_net.cpp
+++ b/src/d_net.cpp
@@ -2319,10 +2319,12 @@ void Net_DoCommand (int type, BYTE **stream, int player)
else
{
const AActor *def = GetDefaultByType (typeinfo);
- AActor *spawned = Spawn (typeinfo,
- source->x + FixedMul (def->radius * 2 + source->radius, finecosine[source->angle>>ANGLETOFINESHIFT]),
- source->y + FixedMul (def->radius * 2 + source->radius, finesine[source->angle>>ANGLETOFINESHIFT]),
- source->z + 8 * FRACUNIT, ALLOW_REPLACE);
+ fixedvec3 spawnpos = source->Vec3Offset(
+ FixedMul (def->radius * 2 + source->radius, finecosine[source->angle>>ANGLETOFINESHIFT]),
+ FixedMul (def->radius * 2 + source->radius, finesine[source->angle>>ANGLETOFINESHIFT]),
+ 8 * FRACUNIT);
+
+ AActor *spawned = Spawn (typeinfo, spawnpos, ALLOW_REPLACE);
if (spawned != NULL)
{
if (type == DEM_SUMMONFRIEND || type == DEM_SUMMONFRIEND2 || type == DEM_SUMMONMBF)
@@ -2373,8 +2375,8 @@ void Net_DoCommand (int type, BYTE **stream, int player)
s = ReadString (stream);
- if (Trace (players[player].mo->x, players[player].mo->y,
- players[player].mo->z + players[player].mo->height - (players[player].mo->height>>2),
+ if (Trace (players[player].mo->X(), players[player].mo->Y(),
+ players[player].mo->Z() + players[player].mo->height - (players[player].mo->height>>2),
players[player].mo->Sector,
vx, vy, vz, 172*FRACUNIT, 0, ML_BLOCKEVERYTHING, players[player].mo,
trace, TRACE_NoSky))
diff --git a/src/d_player.h b/src/d_player.h
index 79932bffac..9a5daa0ab1 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -443,6 +443,8 @@ public:
int killcount, itemcount, secretcount; // for intermission
int damagecount, bonuscount;// for screen flashing
int hazardcount; // for delayed Strife damage
+ int hazardinterval; // Frequency of damage infliction
+ FName hazardtype; // Damage type of last hazardous damage encounter.
int poisoncount; // screen flash for poison damage
FName poisontype; // type of poison damage to apply
FName poisonpaintype; // type of Pain state to enter for poison damage
diff --git a/src/dobject.cpp b/src/dobject.cpp
index 4ca08a79d5..cd7b784a40 100644
--- a/src/dobject.cpp
+++ b/src/dobject.cpp
@@ -388,8 +388,8 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld)
#define SECTOR_CHECK(f,t) \
if (sectors[i].f.p == static_cast(old)) { sectors[i].f = static_cast(notOld); changed++; }
SECTOR_CHECK( SoundTarget, AActor );
- SECTOR_CHECK( CeilingSkyBox, ASkyViewpoint );
- SECTOR_CHECK( FloorSkyBox, ASkyViewpoint );
+ SECTOR_CHECK( SkyBoxes[sector_t::ceiling], ASkyViewpoint );
+ SECTOR_CHECK( SkyBoxes[sector_t::floor], ASkyViewpoint );
SECTOR_CHECK( SecActTarget, ASectorAction );
SECTOR_CHECK( floordata, DSectorEffect );
SECTOR_CHECK( ceilingdata, DSectorEffect );
diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp
index 51b98eee48..49453ca4d3 100644
--- a/src/dobjgc.cpp
+++ b/src/dobjgc.cpp
@@ -677,8 +677,8 @@ size_t DSectorMarker::PropagateMark()
{
sector_t *sec = §ors[SecNum + i];
GC::Mark(sec->SoundTarget);
- GC::Mark(sec->CeilingSkyBox);
- GC::Mark(sec->FloorSkyBox);
+ GC::Mark(sec->SkyBoxes[sector_t::ceiling]);
+ GC::Mark(sec->SkyBoxes[sector_t::floor]);
GC::Mark(sec->SecActTarget);
GC::Mark(sec->floordata);
GC::Mark(sec->ceilingdata);
diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp
index 6cecf1a60f..8b7103d9a0 100644
--- a/src/fragglescript/t_func.cpp
+++ b/src/fragglescript/t_func.cpp
@@ -3145,8 +3145,8 @@ void FParser::SF_MoveCamera(void)
}
// set step variables based on distance and speed
- mobjangle = R_PointToAngle2(cam->x, cam->y, target->x, target->y);
- xydist = R_PointToDist2(target->x - cam->x, target->y - cam->y);
+ mobjangle = cam->AngleTo(target);
+ xydist = cam->Distance2D(target);
xstep = FixedMul(finecosine[mobjangle >> ANGLETOFINESHIFT], movespeed);
ystep = FixedMul(finesine[mobjangle >> ANGLETOFINESHIFT], movespeed);
@@ -4323,44 +4323,12 @@ void FParser::SF_KillInSector()
//==========================================================================
//
// new for GZDoom: Sets a sector's type
-// (Sure, this is not particularly useful. But having it made it possible
-// to fix a few annoying bugs in some old maps ;) )
//
//==========================================================================
void FParser::SF_SectorType(void)
{
- int tagnum, secnum;
- sector_t *sector;
-
- if (CheckArgs(1))
- {
- tagnum = intvalue(t_argv[0]);
-
- // argv is sector tag
- secnum = T_FindFirstSectorFromTag(tagnum);
-
- if(secnum < 0)
- { script_error("sector not found with tagnum %i\n", tagnum); return;}
-
- sector = §ors[secnum];
-
- if(t_argc > 1)
- {
- int i = -1;
- int spec = intvalue(t_argv[1]);
-
- // set all sectors with tag
- FSSectorTagIterator itr(tagnum);
- while ((i = itr.Next()) >= 0)
- {
- sectors[i].special = spec;
- }
- }
-
- t_return.type = svt_int;
- t_return.value.i = sector->special;
- }
+ // I don't think this was ever used publicly so I'm not going to bother fixing it.
}
//==========================================================================
diff --git a/src/fragglescript/t_load.cpp b/src/fragglescript/t_load.cpp
index eedb68f7cf..cd40d809a4 100644
--- a/src/fragglescript/t_load.cpp
+++ b/src/fragglescript/t_load.cpp
@@ -87,7 +87,6 @@ DEFINE_MAP_OPTION(fs_nocheckposition, false)
{
FFsOptions *opt = info->GetOptData("fragglescript");
- parse.ParseAssign();
if (parse.CheckAssign())
{
parse.sc.MustGetNumber();
diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp
index a5ebd058f3..8951a8e885 100644
--- a/src/g_doom/a_doomweaps.cpp
+++ b/src/g_doom/a_doomweaps.cpp
@@ -61,10 +61,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch)
if (linetarget)
{
S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM);
- self->angle = R_PointToAngle2 (self->x,
- self->y,
- linetarget->x,
- linetarget->y);
+ self->angle = self->AngleTo(linetarget);
}
return 0;
}
@@ -235,8 +232,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
// turn to face target
if (!(flags & SF_NOTURN))
{
- angle = R_PointToAngle2(self->x, self->y,
- linetarget->x, linetarget->y);
+ angle = self->AngleTo(linetarget);
if (angle - self->angle > ANG180)
{
if (angle - self->angle < (angle_t)(-ANG90 / 20))
diff --git a/src/g_doom/a_lostsoul.cpp b/src/g_doom/a_lostsoul.cpp
index a7bea635bf..9bf89408fd 100644
--- a/src/g_doom/a_lostsoul.cpp
+++ b/src/g_doom/a_lostsoul.cpp
@@ -36,7 +36,7 @@ void A_SkullAttack(AActor *self, fixed_t speed)
an = self->angle >> ANGLETOFINESHIFT;
self->velx = FixedMul (speed, finecosine[an]);
self->vely = FixedMul (speed, finesine[an]);
- dist = P_AproxDistance (dest->x - self->x, dest->y - self->y);
+ dist = self->AproxDistance (dest);
dist = dist / speed;
if (dist < 1)
diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp
index 72b4c608d0..d914d0aa4f 100644
--- a/src/g_doom/a_painelemental.cpp
+++ b/src/g_doom/a_painelemental.cpp
@@ -112,7 +112,7 @@ void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *spawntype, int
box.Top() < ld->bbox[BOXBOTTOM] ||
box.Bottom() > ld->bbox[BOXTOP]))
{
- if (P_PointOnLineSide(self->x,self->y,ld) != P_PointOnLineSide(x,y,ld))
+ if (P_PointOnLineSidePrecise(self->x,self->y,ld) != P_PointOnLineSidePrecise(x,y,ld))
return; // line blocks trajectory // ^
}
}
diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp
index 414f8f11b1..c96a23e23b 100644
--- a/src/g_doom/a_revenant.cpp
+++ b/src/g_doom/a_revenant.cpp
@@ -82,7 +82,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer)
return 0;
// change angle
- exact = R_PointToAngle2 (self->x, self->y, dest->x, dest->y);
+ exact = self->AngleTo(dest);
if (exact != self->angle)
{
@@ -107,10 +107,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer)
if (!(self->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{
// change slope
- dist = P_AproxDistance (dest->x - self->x,
- dest->y - self->y);
-
- dist = dist / self->Speed;
+ dist = self->AproxDistance (dest) / self->Speed;
if (dist < 1)
dist = 1;
diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp
index 6fbf77cfd0..43eec76e1f 100644
--- a/src/g_doom/a_scriptedmarine.cpp
+++ b/src/g_doom/a_scriptedmarine.cpp
@@ -293,7 +293,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw)
S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM);
// turn to face target
- angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y);
+ angle = self->AngleTo(linetarget);
if (angle - self->angle > ANG180)
{
if (angle - self->angle < (angle_t)(-ANG90/20))
@@ -344,7 +344,8 @@ static void MarinePunch(AActor *self, int damagemul)
if (linetarget)
{
S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM);
- self->angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y);
+ self->angle = self->AngleTo(linetarget);
+
}
}
diff --git a/src/g_doomedmap.cpp b/src/g_doomedmap.cpp
index b72627c37f..cce2889c79 100644
--- a/src/g_doomedmap.cpp
+++ b/src/g_doomedmap.cpp
@@ -81,7 +81,7 @@ struct MapinfoEdMapItem
{
FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet.
short special;
- bool argsdefined;
+ signed char argsdefined;
int args[5];
// These are for error reporting. We must store the file information because it's no longer available when these items get resolved.
FString filename;
@@ -181,14 +181,14 @@ void FMapInfoParser::ParseDoomEdNums()
editem.special = -1;
}
memset(editem.args, 0, sizeof(editem.args));
- editem.argsdefined = false;
+ editem.argsdefined = 0;
int minargs = 0;
int maxargs = 5;
FString specialname;
if (sc.CheckString(","))
{
- editem.argsdefined = true; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing.
+ editem.argsdefined = 5; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing.
if (editem.special < 0) editem.special = 0;
if (!sc.CheckNumber())
{
@@ -221,7 +221,14 @@ void FMapInfoParser::ParseDoomEdNums()
editem.args[i] = sc.Number;
i++;
if (!sc.CheckString(",")) break;
+ // special check for the ambient sounds which combine the arg being set here with the ones on the mapthing.
+ if (sc.CheckString("+"))
+ {
+ editem.argsdefined = i;
+ break;
+ }
sc.MustGetNumber();
+
}
if (specialname.IsNotEmpty() && (i < minargs || i > maxargs))
{
diff --git a/src/g_game.cpp b/src/g_game.cpp
index 3012d04ff1..64cdd43c74 100644
--- a/src/g_game.cpp
+++ b/src/g_game.cpp
@@ -1179,7 +1179,7 @@ void G_Ticker ()
}
if (players[i].mo)
{
- DWORD sum = rngsum + players[i].mo->x + players[i].mo->y + players[i].mo->z
+ DWORD sum = rngsum + players[i].mo->X() + players[i].mo->Y() + players[i].mo->Z()
+ players[i].mo->angle + players[i].mo->pitch;
sum ^= players[i].health;
consistancy[i][buf] = sum;
@@ -1438,13 +1438,13 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing)
if (!players[playernum].mo)
{ // first spawn of level, before corpses
for (i = 0; i < playernum; i++)
- if (players[i].mo && players[i].mo->x == x && players[i].mo->y == y)
+ if (players[i].mo && players[i].mo->X() == x && players[i].mo->Y() == y)
return false;
return true;
}
- oldz = players[playernum].mo->z; // [RH] Need to save corpse's z-height
- players[playernum].mo->z = z; // [RH] Checks are now full 3-D
+ oldz = players[playernum].mo->Z(); // [RH] Need to save corpse's z-height
+ players[playernum].mo->SetZ(z); // [RH] Checks are now full 3-D
// killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid
// corpse to detect collisions with other players in DM starts
@@ -1456,7 +1456,7 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing)
players[playernum].mo->flags |= MF_SOLID;
i = P_CheckPosition(players[playernum].mo, x, y);
players[playernum].mo->flags &= ~MF_SOLID;
- players[playernum].mo->z = oldz; // [RH] Restore corpse's height
+ players[playernum].mo->SetZ(oldz); // [RH] Restore corpse's height
if (!i)
return false;
@@ -1482,8 +1482,7 @@ static fixed_t PlayersRangeFromSpot (FPlayerStart *spot)
if (!playeringame[i] || !players[i].mo || players[i].health <= 0)
continue;
- distance = P_AproxDistance (players[i].mo->x - spot->x,
- players[i].mo->y - spot->y);
+ distance = players[i].mo->AproxDistance (spot->x, spot->y);
if (distance < closest)
closest = distance;
@@ -1716,6 +1715,8 @@ void G_DoPlayerPop(int playernum)
// [RH] Make the player disappear
FBehavior::StaticStopMyScripts(players[playernum].mo);
+ // [RH] Let the scripts know the player left
+ FBehavior::StaticStartTypedScripts(SCRIPT_Disconnect, players[playernum].mo, true, playernum, true);
if (players[playernum].mo != NULL)
{
P_DisconnectEffect(players[playernum].mo);
@@ -1729,8 +1730,6 @@ void G_DoPlayerPop(int playernum)
players[playernum].mo = NULL;
players[playernum].camera = NULL;
}
- // [RH] Let the scripts know the player left
- FBehavior::StaticStartTypedScripts(SCRIPT_Disconnect, NULL, true, playernum);
}
void G_ScreenShot (char *filename)
diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp
index f5c7ff29f0..c905134fef 100644
--- a/src/g_heretic/a_chicken.cpp
+++ b/src/g_heretic/a_chicken.cpp
@@ -189,8 +189,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1)
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget);
if (linetarget)
{
- player->mo->angle = R_PointToAngle2 (player->mo->x,
- player->mo->y, linetarget->x, linetarget->y);
+ player->mo->angle = player->mo->AngleTo(linetarget);
}
P_PlayPeck (player->mo);
player->chickenPeck = 12;
@@ -225,8 +224,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2)
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget);
if (linetarget)
{
- player->mo->angle = R_PointToAngle2 (player->mo->x,
- player->mo->y, linetarget->x, linetarget->y);
+ player->mo->angle = player->mo->AngleTo(linetarget);
}
P_PlayPeck (player->mo);
player->chickenPeck = 12;
diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp
index 1ce4074d71..c081acf3ef 100644
--- a/src/g_heretic/a_hereticweaps.cpp
+++ b/src/g_heretic/a_hereticweaps.cpp
@@ -94,8 +94,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack)
{
//S_StartSound(player->mo, sfx_stfhit);
// turn to face target
- self->angle = R_PointToAngle2 (self->x,
- self->y, linetarget->x, linetarget->y);
+ self->angle = self->AngleTo(linetarget);
}
return 0;
}
@@ -325,8 +324,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack)
S_Sound (self, CHAN_AUTO, "weapons/gauntletshit", 1, ATTN_NORM);
}
// turn to face target
- angle = R_PointToAngle2 (self->x, self->y,
- linetarget->x, linetarget->y);
+ angle = self->AngleTo(linetarget);
if (angle-self->angle > ANG180)
{
if ((int)(angle-self->angle) < -ANG90/20)
@@ -684,8 +682,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact)
}
else
{ // Seek
- angle = R_PointToAngle2(self->x, self->y,
- target->x, target->y);
+ self->angle = self->AngleTo(target);
newAngle = true;
}
}
@@ -698,8 +695,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact)
if (linetarget && self->target != linetarget)
{
self->tracer = linetarget;
- angle = R_PointToAngle2 (self->x, self->y,
- linetarget->x, linetarget->y);
+ angle = self->AngleTo(linetarget);
newAngle = true;
break;
}
@@ -1163,7 +1159,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling)
F3DFloor * rover = self->Sector->e->XFloor.ffloors[i];
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
- if ((foo = rover->bottom.plane->ZatPoint(self->x, self->y)) >= (self->z + self->height))
+ if ((foo = rover->bottom.plane->ZatPoint(self)) >= (self->z + self->height))
{
self->z = foo + 4*FRACUNIT;
self->bouncecount = i;
diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp
index c8ddb359fe..97b008b112 100644
--- a/src/g_heretic/a_ironlich.cpp
+++ b/src/g_heretic/a_ironlich.cpp
@@ -93,8 +93,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack)
P_TraceBleed (newdam > 0 ? newdam : damage, target, self);
return 0;
}
- dist = P_AproxDistance (self->x-target->x, self->y-target->y)
- > 8*64*FRACUNIT;
+ dist = self->AproxDistance (target) > 8*64*FRACUNIT;
randAttack = pr_atk ();
if (randAttack < atkResolve1[dist])
{ // Ice ball
diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp
index 58184f45a6..e072743c5a 100644
--- a/src/g_hexen/a_blastradius.cpp
+++ b/src/g_hexen/a_blastradius.cpp
@@ -33,13 +33,13 @@ void BlastActor (AActor *victim, fixed_t strength, fixed_t speed, AActor *Owner,
return;
}
- angle = R_PointToAngle2 (Owner->x, Owner->y, victim->x, victim->y);
+ angle = Owner->AngleTo(victim);
angle >>= ANGLETOFINESHIFT;
victim->velx = FixedMul (speed, finecosine[angle]);
victim->vely = FixedMul (speed, finesine[angle]);
// Spawn blast puff
- ang = R_PointToAngle2 (victim->x, victim->y, Owner->x, Owner->y);
+ ang = victim->AngleTo(Owner);
ang >>= ANGLETOFINESHIFT;
x = victim->x + FixedMul (victim->radius+FRACUNIT, finecosine[ang]);
y = victim->y + FixedMul (victim->radius+FRACUNIT, finesine[ang]);
@@ -145,7 +145,7 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast)
{ // Must be monster, player, missile, touchy or vulnerable
continue;
}
- dist = P_AproxDistance (self->x - mo->x, self->y - mo->y);
+ dist = self->AproxDistance (mo);
if (dist > radius)
{ // Out of range
continue;
diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp
index 849890ce99..f5436dae79 100644
--- a/src/g_hexen/a_clericholy.cpp
+++ b/src/g_hexen/a_clericholy.cpp
@@ -274,14 +274,12 @@ static void CHolyTailFollow (AActor *actor, fixed_t dist)
child = actor->tracer;
if (child)
{
- an = R_PointToAngle2(actor->x, actor->y, child->x,
- child->y)>>ANGLETOFINESHIFT;
- oldDistance = P_AproxDistance (child->x-actor->x, child->y-actor->y);
+ an = actor->AngleTo(child) >> ANGLETOFINESHIFT;
+ oldDistance = child->AproxDistance (actor);
if (P_TryMove (child, actor->x+FixedMul(dist, finecosine[an]),
actor->y+FixedMul(dist, finesine[an]), true))
{
- newDistance = P_AproxDistance (child->x-actor->x,
- child->y-actor->y)-FRACUNIT;
+ newDistance = child->AproxDistance (actor)-FRACUNIT;
if (oldDistance < FRACUNIT)
{
if (child->z < actor->z)
@@ -440,7 +438,7 @@ static void CHolySeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax)
deltaZ = -15*FRACUNIT;
}
}
- dist = P_AproxDistance (target->x-actor->x, target->y-actor->y);
+ dist = actor->AproxDistance (target);
dist = dist / actor->Speed;
if (dist < 1)
{
diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp
index 2cc30a7ae2..a5a5fdfece 100644
--- a/src/g_hexen/a_clericstaff.cpp
+++ b/src/g_hexen/a_clericstaff.cpp
@@ -77,7 +77,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck)
P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, puff, false, &linetarget);
if (linetarget != NULL)
{
- pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y);
+ pmo->angle = pmo->AngleTo(linetarget);
if (((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0))|| linetarget->flags3&MF3_ISMONSTER)
&& (!(linetarget->flags2&(MF2_DORMANT|MF2_INVULNERABLE))))
{
@@ -107,7 +107,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck)
P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, puff, false, &linetarget);
if (linetarget != NULL)
{
- pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y);
+ pmo->angle = pmo->AngleTo(linetarget);
if ((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER)
{
newLife = player->health+(damage>>4);
diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp
index 77f4674742..312a151bdf 100644
--- a/src/g_hexen/a_dragon.cpp
+++ b/src/g_hexen/a_dragon.cpp
@@ -59,28 +59,21 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax)
angle = actor->angle>>ANGLETOFINESHIFT;
actor->velx = FixedMul (actor->Speed, finecosine[angle]);
actor->vely = FixedMul (actor->Speed, finesine[angle]);
+ dist = actor->AproxDistance (target) / actor->Speed;
if (actor->z+actor->height < target->z ||
target->z+target->height < actor->z)
{
- dist = P_AproxDistance(target->x-actor->x, target->y-actor->y);
- dist = dist/actor->Speed;
if (dist < 1)
{
dist = 1;
}
actor->velz = (target->z - actor->z)/dist;
}
- else
- {
- dist = P_AproxDistance (target->x-actor->x, target->y-actor->y);
- dist = dist/actor->Speed;
- }
if (target->flags&MF_SHOOTABLE && pr_dragonseek() < 64)
{ // attack the destination mobj if it's attackable
AActor *oldTarget;
- if (absangle(actor->angle-R_PointToAngle2(actor->x, actor->y,
- target->x, target->y)) < ANGLE_45/2)
+ if (absangle(actor->angle - actor->AngleTo(target)) < ANGLE_45/2)
{
oldTarget = actor->target;
actor->target = target;
@@ -105,8 +98,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax)
{
AActor *bestActor = NULL;
bestAngle = ANGLE_MAX;
- angleToTarget = R_PointToAngle2(actor->x, actor->y,
- actor->target->x, actor->target->y);
+ angleToTarget = actor->AngleTo(actor->target);
for (i = 0; i < 5; i++)
{
if (!target->args[i])
@@ -119,8 +111,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax)
{
continue;
}
- angleToSpot = R_PointToAngle2(actor->x, actor->y,
- mo->x, mo->y);
+ angleToSpot = actor->AngleTo(mo);
if (absangle(angleToSpot-angleToTarget) < bestAngle)
{
bestAngle = absangle(angleToSpot-angleToTarget);
@@ -201,8 +192,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight)
self->target = NULL;
return 0;
}
- angle = R_PointToAngle2(self->x, self->y, self->target->x,
- self->target->y);
+ angle = self->AngleTo(self->target);
if (absangle(self->angle-angle) < ANGLE_45/2 && self->CheckMeleeRange())
{
int damage = pr_dragonflight.HitDice (8);
diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp
index f7f28acdae..944a4aa459 100644
--- a/src/g_hexen/a_fighterplayer.cpp
+++ b/src/g_hexen/a_fighterplayer.cpp
@@ -30,7 +30,7 @@ void AdjustPlayerAngle (AActor *pmo, AActor *linetarget)
angle_t angle;
int difference;
- angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y);
+ angle = pmo->AngleTo(linetarget);
difference = (int)angle - (int)pmo->angle;
if (abs(difference) > MAX_ANGLE_ADJUST)
{
diff --git a/src/g_hexen/a_firedemon.cpp b/src/g_hexen/a_firedemon.cpp
index 714ece7b35..f06c2f28ec 100644
--- a/src/g_hexen/a_firedemon.cpp
+++ b/src/g_hexen/a_firedemon.cpp
@@ -169,12 +169,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase)
{
self->special2 = 0;
self->velx = self->vely = 0;
- dist = P_AproxDistance (self->x - target->x, self->y - target->y);
+ dist = self->AproxDistance (target);
if (dist < FIREDEMON_ATTACK_RANGE)
{
if (pr_firedemonchase() < 30)
{
- ang = R_PointToAngle2 (self->x, self->y, target->x, target->y);
+ ang = self->AngleTo(target);
if (pr_firedemonchase() < 128)
ang += ANGLE_90;
else
diff --git a/src/g_hexen/a_flies.cpp b/src/g_hexen/a_flies.cpp
index c7437235b3..05e59f19c3 100644
--- a/src/g_hexen/a_flies.cpp
+++ b/src/g_hexen/a_flies.cpp
@@ -84,7 +84,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz)
return 0;
}
- angle_t ang = R_PointToAngle2(self->x, self->y, targ->x, targ->y);
+ angle_t ang = self->AngleTo(targ);
self->angle = ang;
self->args[0]++;
ang >>= ANGLETOFINESHIFT;
diff --git a/src/g_hexen/a_healingradius.cpp b/src/g_hexen/a_healingradius.cpp
index a4e66eb103..32e670e5c3 100644
--- a/src/g_hexen/a_healingradius.cpp
+++ b/src/g_hexen/a_healingradius.cpp
@@ -42,7 +42,7 @@ bool AArtiHealingRadius::Use (bool pickup)
if (playeringame[i] &&
players[i].mo != NULL &&
players[i].mo->health > 0 &&
- P_AproxDistance (players[i].mo->x - Owner->x, players[i].mo->y - Owner->y) <= HEAL_RADIUS_DIST)
+ players[i].mo->AproxDistance (Owner) <= HEAL_RADIUS_DIST)
{
// Q: Is it worth it to make this selectable as a player property?
// A: Probably not - but it sure doesn't hurt.
diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp
index 824921e83d..206d423570 100644
--- a/src/g_hexen/a_heresiarch.cpp
+++ b/src/g_hexen/a_heresiarch.cpp
@@ -674,8 +674,7 @@ void A_SorcOffense2(AActor *actor)
if (mo)
{
mo->special2 = 35*5/2; // 5 seconds
- dist = P_AproxDistance(dest->x - mo->x, dest->y - mo->y);
- dist = dist/mo->Speed;
+ dist = mo->AproxDistance(dest) / mo->Speed;
if(dist < 1) dist = 1;
mo->velz = (dest->z - mo->z) / dist;
}
diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp
index abd8b70ee7..deaa078ab9 100644
--- a/src/g_hexen/a_hexenspecialdecs.cpp
+++ b/src/g_hexen/a_hexenspecialdecs.cpp
@@ -117,8 +117,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck)
if (playeringame[i])
{
AActor *pmo = players[i].mo;
- if (P_CheckSight (self, pmo) && (absangle(R_PointToAngle2 (pmo->x,
- pmo->y, self->x, self->y) - pmo->angle) <= ANGLE_45))
+ if (P_CheckSight (self, pmo) && (absangle(pmo->AngleTo(self) - pmo->angle) <= ANGLE_45))
{ // Previous state (pottery bit waiting state)
self->SetState (self->state - 1);
return 0;
diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp
index 01cc532ff1..e9021b4b0c 100644
--- a/src/g_hexen/a_korax.cpp
+++ b/src/g_hexen/a_korax.cpp
@@ -409,8 +409,7 @@ void A_KSpiritSeeker (AActor *actor, angle_t thresh, angle_t turnMax)
deltaZ = -15*FRACUNIT;
}
}
- dist = P_AproxDistance (target->x-actor->x, target->y-actor->y);
- dist = dist/actor->Speed;
+ dist = actor->AproxDistance (target) / actor->Speed;
if (dist < 1)
{
dist = 1;
@@ -516,7 +515,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z,
z -= source->floorclip;
th = Spawn (type, x, y, z, ALLOW_REPLACE);
th->target = source; // Originator
- an = R_PointToAngle2(x, y, dest->x, dest->y);
+ an = source->AngleXYTo(x, y, dest);
if (dest->flags & MF_SHADOW)
{ // Invisible target
an += pr_kmissile.Random2()<<21;
@@ -525,8 +524,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z,
an >>= ANGLETOFINESHIFT;
th->velx = FixedMul (th->Speed, finecosine[an]);
th->vely = FixedMul (th->Speed, finesine[an]);
- dist = P_AproxDistance (dest->x - x, dest->y - y);
- dist = dist/th->Speed;
+ dist = dest->AproxDistance (x, y, source) / th->Speed;
if (dist < 1)
{
dist = 1;
diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp
index 0a31ef1433..0639048a12 100644
--- a/src/g_hexen/a_magelightning.cpp
+++ b/src/g_hexen/a_magelightning.cpp
@@ -195,7 +195,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningClip)
}
else
{
- self->angle = R_PointToAngle2(self->x, self->y, target->x, target->y);
+ self->angle = self->AngleTo(target);
self->velx = 0;
self->vely = 0;
P_ThrustMobj (self, self->angle, self->Speed>>1);
diff --git a/src/g_level.cpp b/src/g_level.cpp
index aba58e810a..03474a5b7a 100644
--- a/src/g_level.cpp
+++ b/src/g_level.cpp
@@ -1232,6 +1232,7 @@ void G_FinishTravel ()
pawn->dropoffz = pawndup->dropoffz;
pawn->floorsector = pawndup->floorsector;
pawn->floorpic = pawndup->floorpic;
+ pawn->floorterrain = pawndup->floorterrain;
pawn->ceilingsector = pawndup->ceilingsector;
pawn->ceilingpic = pawndup->ceilingpic;
pawn->floorclip = pawndup->floorclip;
diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp
index b54daffeb3..7447fb108a 100644
--- a/src/g_raven/a_minotaur.cpp
+++ b/src/g_raven/a_minotaur.cpp
@@ -193,7 +193,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide)
{
S_Sound (self, CHAN_WEAPON, "minotaur/sight", 1, ATTN_NORM);
}
- dist = P_AproxDistance (self->x-target->x, self->y-target->y);
+ dist = self->AproxDistance (target);
if (target->z+target->height > self->z
&& target->z+target->height < self->z+self->height
&& dist < (friendly ? 16*64*FRACUNIT : 8*64*FRACUNIT)
@@ -413,7 +413,7 @@ void P_MinotaurSlam (AActor *source, AActor *target)
fixed_t thrust;
int damage;
- angle = R_PointToAngle2 (source->x, source->y, target->x, target->y);
+ angle = source->AngleTo(target);
angle >>= ANGLETOFINESHIFT;
thrust = 16*FRACUNIT+(pr_minotaurslam()<<10);
target->velx += FixedMul (thrust, finecosine[angle]);
@@ -517,7 +517,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook)
mo = player->mo;
if (mo == master) continue;
if (mo->health <= 0) continue;
- dist = P_AproxDistance(self->x - mo->x, self->y - mo->y);
+ dist = self->AproxDistance(mo);
if (dist > MINOTAUR_LOOK_DIST) continue;
self->target = mo;
break;
@@ -542,7 +542,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook)
if (!(mo->flags3 & MF3_ISMONSTER)) continue;
if (mo->health <= 0) continue;
if (!(mo->flags & MF_SHOOTABLE)) continue;
- dist = P_AproxDistance (self->x - mo->x, self->y - mo->y);
+ dist = self->AproxDistance(mo);
if (dist > MINOTAUR_LOOK_DIST) continue;
if ((mo == master) || (mo == self)) continue;
if ((mo->flags5 & MF5_SUMMONEDMONSTER) && (mo->tracer == master)) continue;
diff --git a/src/g_shared/a_lightning.cpp b/src/g_shared/a_lightning.cpp
index e7c598d3e8..33d51c02d9 100644
--- a/src/g_shared/a_lightning.cpp
+++ b/src/g_shared/a_lightning.cpp
@@ -139,7 +139,7 @@ void DLightningThinker::LightningFlash ()
for (i = numsectors, j = 0; i > 0; --i, ++j, ++tempSec)
{
// allow combination of the lightning sector specials with bit masks
- int special = tempSec->special & 0xff;
+ int special = tempSec->special;
if (tempSec->GetTexture(sector_t::ceiling) == skyflatnum
|| special == Light_IndoorLightning1
|| special == Light_IndoorLightning2
diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp
index 3c8d704aa7..195f3ccbfd 100644
--- a/src/g_shared/a_quake.cpp
+++ b/src/g_shared/a_quake.cpp
@@ -129,7 +129,7 @@ void DEarthquake::Tick ()
AActor *victim = players[i].mo;
fixed_t dist;
- dist = P_AproxDistance (victim->x - m_Spot->x, victim->y - m_Spot->y);
+ dist = m_Spot->AproxDistance (victim, true);
// Check if in damage radius
if (dist < m_DamageRadius && victim->z <= victim->floorz)
{
@@ -242,8 +242,7 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jigger
{
if (quake->m_Spot != NULL)
{
- fixed_t dist = P_AproxDistance (victim->x - quake->m_Spot->x,
- victim->y - quake->m_Spot->y);
+ fixed_t dist = quake->m_Spot->AproxDistance (victim, true);
if (dist < quake->m_TremorRadius)
{
++count;
diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h
index d23b8291cf..acb4faf0f7 100644
--- a/src/g_shared/a_sharedglobal.h
+++ b/src/g_shared/a_sharedglobal.h
@@ -100,6 +100,20 @@ public:
TObjPtr Mate;
};
+// For an EE compatible linedef based definition.
+class ASkyCamCompat : public ASkyViewpoint
+{
+ DECLARE_CLASS (ASkyCamCompat, ASkyViewpoint)
+
+public:
+ void BeginPlay ()
+ {
+ // Do not call the SkyViewpoint's super method because it would trash our setup
+ AActor::BeginPlay();
+ }
+};
+
+
class AStackPoint : public ASkyViewpoint
{
DECLARE_CLASS (AStackPoint, ASkyViewpoint)
diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp
index 54661ea147..a8c8ebd55d 100644
--- a/src/g_shared/a_skies.cpp
+++ b/src/g_shared/a_skies.cpp
@@ -37,6 +37,7 @@
#include "p_local.h"
#include "p_lnspec.h"
#include "farchive.h"
+#include "r_sky.h"
// arg0 = Visibility*4 for this skybox
@@ -66,13 +67,13 @@ void ASkyViewpoint::Destroy ()
// remove all sector references to ourselves.
for (int i = 0; i linecount; i++)
- {
- refline = Sector->lines[i];
- if (refline->special == Sector_SetPortal && refline->args[1] == 2)
- {
- // We found the setup linedef for this skybox, so let's use it for our init.
- int skybox_id = refline->args[0];
-
- // Then, change the alpha
- alpha = refline->args[4];
-
- // Finally, skyboxify all tagged sectors
- // This involves changing their texture to the sky flat, because while
- // EE works with any texture for its skybox portals, ZDoom doesn't.
- FSectorTagIterator it(skybox_id);
- int secnum;
- while ((secnum = it.Next()) >= 0)
- {
- // plane: 0=floor, 1=ceiling, 2=both
- if (refline->args[2] == 1 || refline->args[2] == 2)
- {
- sectors[secnum].CeilingSkyBox = this;
- sectors[secnum].SetTexture(sector_t::ceiling, skyflatnum, false);
- }
- if (refline->args[2] == 0 || refline->args[2] == 2)
- {
- sectors[secnum].FloorSkyBox = this;
- sectors[secnum].SetTexture(sector_t::floor, skyflatnum, false);
- }
- }
- }
- }
- }
- // Do not call the SkyViewpoint's super method because it would trash our setup
- AActor::BeginPlay();
-}
//---------------------------------------------------------------------------
@@ -185,12 +129,12 @@ void ASkyPicker::PostBeginPlay ()
{
if (0 == (args[1] & 2))
{
- Sector->CeilingSkyBox = box;
+ Sector->SkyBoxes[sector_t::ceiling] = box;
if (box == NULL) Sector->MoreFlags |= SECF_NOCEILINGSKYBOX; // sector should ignore the level's default skybox
}
if (0 == (args[1] & 1))
{
- Sector->FloorSkyBox = box;
+ Sector->SkyBoxes[sector_t::floor] = box;
if (box == NULL) Sector->MoreFlags |= SECF_NOFLOORSKYBOX; // sector should ignore the level's default skybox
}
}
diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp
index 08d95b4a36..d157562386 100644
--- a/src/g_shared/a_specialspot.cpp
+++ b/src/g_shared/a_specialspot.cpp
@@ -158,7 +158,7 @@ struct FSpotList
while (true)
{
- distance = P_AproxDistance(Spots[i]->x - x, Spots[i]->y - y);
+ distance = Spots[i]->AproxDistance(x, y);
if ((distance >= mindist) && ((maxdist == 0) || (distance <= maxdist))) break;
diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp
index 214c452ddb..10e87b1b85 100644
--- a/src/g_shared/sbar_mugshot.cpp
+++ b/src/g_shared/sbar_mugshot.cpp
@@ -366,7 +366,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags)
if (player->mo != NULL)
{
// The next 12 lines are from the Doom statusbar code.
- badguyangle = R_PointToAngle2(player->mo->x, player->mo->y, player->attacker->x, player->attacker->y);
+ badguyangle = player->mo->AngleTo(player->attacker);
if (badguyangle > player->mo->angle)
{
// whether right or left
diff --git a/src/g_strife/a_crusader.cpp b/src/g_strife/a_crusader.cpp
index 87da6b5723..9c5e0ca370 100644
--- a/src/g_strife/a_crusader.cpp
+++ b/src/g_strife/a_crusader.cpp
@@ -11,9 +11,9 @@
static bool CrusaderCheckRange (AActor *self)
{
- if (P_CheckSight (self, self->target) && self->reactiontime == 0)
+ if (self->reactiontime == 0 && P_CheckSight (self, self->target))
{
- return P_AproxDistance (self->x - self->target->x, self->y - self->target->y) < 264*FRACUNIT;
+ return self->AproxDistance (self->target) < 264*FRACUNIT;
}
return false;
}
diff --git a/src/g_strife/a_inquisitor.cpp b/src/g_strife/a_inquisitor.cpp
index ed2089c5d0..01eb3fca2b 100644
--- a/src/g_strife/a_inquisitor.cpp
+++ b/src/g_strife/a_inquisitor.cpp
@@ -23,7 +23,7 @@ bool InquisitorCheckDistance (AActor *self)
{
if (self->reactiontime == 0 && P_CheckSight (self, self->target))
{
- return P_AproxDistance (self->x - self->target->x, self->y - self->target->y) < 264*FRACUNIT;
+ return self->AproxDistance (self->target) < 264*FRACUNIT;
}
return false;
}
@@ -96,7 +96,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump)
speed = self->Speed * 2/3;
self->velx += FixedMul (speed, finecosine[an]);
self->vely += FixedMul (speed, finesine[an]);
- dist = P_AproxDistance (self->target->x - self->x, self->target->y - self->y);
+ dist = self->AproxDistance (self->target);
dist /= speed;
if (dist < 1)
{
diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp
index f344211676..d88b9f759e 100644
--- a/src/g_strife/a_spectral.cpp
+++ b/src/g_strife/a_spectral.cpp
@@ -104,7 +104,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2)
return 0;
// change angle
- exact = R_PointToAngle2 (self->x, self->y, dest->x, dest->y);
+ exact = self->AngleTo(dest);
if (exact != self->angle)
{
@@ -129,8 +129,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2)
if (!(self->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{
// change slope
- dist = P_AproxDistance (dest->x - self->x, dest->y - self->y);
- dist /= self->Speed;
+ dist = self->AproxDistance (dest) / self->Speed;
if (dist < 1)
{
diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp
index 78cda3323d..f1ddf1006c 100644
--- a/src/g_strife/a_strifestuff.cpp
+++ b/src/g_strife/a_strifestuff.cpp
@@ -657,13 +657,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain)
sector_t *sec = self->Sector;
- if (self->z == sec->floorplane.ZatPoint (self->x, self->y))
+ if (self->z == sec->floorplane.ZatPoint(self))
{
- if ((sec->special & 0xFF) == Damage_InstantDeath)
+ if (sec->special == Damage_InstantDeath)
{
- P_DamageMobj (self, NULL, NULL, 999, NAME_None);
+ P_DamageMobj (self, NULL, NULL, 999, NAME_InstantDeath);
}
- else if ((sec->special & 0xFF) == Scroll_StrifeCurrent)
+ else if (sec->special == Scroll_StrifeCurrent)
{
int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
fixed_t speed = (anglespeed % 10) << (FRACBITS - 4);
diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp
index 8e5e7bfefb..4eaa141c81 100644
--- a/src/g_strife/a_strifeweapons.cpp
+++ b/src/g_strife/a_strifeweapons.cpp
@@ -120,10 +120,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger)
S_Sound (self, CHAN_WEAPON,
linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit",
1, ATTN_NORM);
- self->angle = R_PointToAngle2 (self->x,
- self->y,
- linetarget->x,
- linetarget->y);
+ self->angle = self->AngleTo(linetarget);
self->flags |= MF_JUSTATTACKED;
P_DaggerAlert (self, linetarget);
}
diff --git a/src/info.h b/src/info.h
index 2af62c8244..b567bd05a0 100644
--- a/src/info.h
+++ b/src/info.h
@@ -280,7 +280,7 @@ struct FDoomEdEntry
{
PClassActor *Type;
short Special;
- bool ArgsDefined;
+ signed char ArgsDefined;
int Args[5];
};
diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp
index 151815549a..fe334012b8 100644
--- a/src/intermission/intermission.cpp
+++ b/src/intermission/intermission.cpp
@@ -329,6 +329,7 @@ void DIntermissionScreenText::Drawer ()
int c;
const FRemapTable *range;
const char *ch = mText;
+ const int kerning = SmallFont->GetDefaultKerning();
// Count number of rows in this text. Since it does not word-wrap, we just count
// line feed characters.
@@ -380,6 +381,7 @@ void DIntermissionScreenText::Drawer ()
}
pic = SmallFont->GetChar (c, &w);
+ w += kerning;
w *= CleanXfac;
if (cx + w > SCREENWIDTH)
continue;
diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp
index d6cb756cac..22a70740da 100644
--- a/src/m_cheat.cpp
+++ b/src/m_cheat.cpp
@@ -580,7 +580,7 @@ void GiveSpawner (player_t *player, PClassInventory *type, int amount)
}
AInventory *item = static_cast
- (Spawn (type, player->mo->x, player->mo->y, player->mo->z, NO_REPLACE));
+ (Spawn (type, player->mo->X(), player->mo->Y(), player->mo->Z(), NO_REPLACE));
if (item != NULL)
{
if (amount > 0)
diff --git a/src/m_random.h b/src/m_random.h
index b5e21c63c9..452ef41fc5 100644
--- a/src/m_random.h
+++ b/src/m_random.h
@@ -57,7 +57,9 @@ public:
// Returns a random number in the range [0,mod)
int operator() (int mod)
{
- return GenRand32() % mod;
+ return (0 == mod)
+ ? 0
+ : (GenRand32() % mod);
}
// Returns rand# - rand#
diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h
index c63359f4b4..0b0b57759d 100644
--- a/src/menu/optionmenuitems.h
+++ b/src/menu/optionmenuitems.h
@@ -32,6 +32,7 @@
**
*/
#include "v_text.h"
+#include "gstrings.h"
void M_DrawConText (int color, int x, int y, const char *str);
@@ -199,6 +200,7 @@ public:
{
text = (*opt)->mValues[Selection].Text;
}
+ if (*text == '$') text = GStrings(text + 1);
screen->DrawText (SmallFont, OptionSettings.mFontColorValue, indent + CURSORSPACE, y,
text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay, TAG_DONE);
return indent;
@@ -503,6 +505,7 @@ public:
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
const char *txt = mCurrent? (const char*)mAltText : mLabel;
+ if (*txt == '$') txt = GStrings(txt + 1);
int w = SmallFont->StringWidth(txt) * CleanXfac_1;
int x = (screen->GetWidth() - w) / 2;
screen->DrawText (SmallFont, mColor, x, y, txt, DTA_CleanNoMove_1, true, TAG_DONE);
diff --git a/src/namedef.h b/src/namedef.h
index 817c629926..d06ca9ccc5 100644
--- a/src/namedef.h
+++ b/src/namedef.h
@@ -518,6 +518,14 @@ xx(floorplane_a)
xx(floorplane_b)
xx(floorplane_c)
xx(floorplane_d)
+xx(damageamount)
+xx(damagetype)
+xx(damageinterval)
+xx(leakiness)
+xx(damageterraineffect)
+xx(damagehazard)
+xx(floorterrain)
+xx(ceilingterrain)
// USDF keywords
xx(Amount)
diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp
index 5b29959cbe..abc4d5c595 100644
--- a/src/p_3dfloors.cpp
+++ b/src/p_3dfloors.cpp
@@ -331,23 +331,22 @@ void P_PlayerOnSpecial3DFloor(player_t* player)
if(rover->flags & FF_SOLID)
{
// Player must be on top of the floor to be affected...
- if(player->mo->z != rover->top.plane->ZatPoint(player->mo->x, player->mo->y)) continue;
+ if(player->mo->Z() != rover->top.plane->ZatPoint(player->mo)) continue;
}
else
{
//Water and DEATH FOG!!! heh
- if (player->mo->z > rover->top.plane->ZatPoint(player->mo->x, player->mo->y) ||
- (player->mo->z + player->mo->height) < rover->bottom.plane->ZatPoint(player->mo->x, player->mo->y))
+ if (player->mo->Z() > rover->top.plane->ZatPoint(player->mo) ||
+ (player->mo->Z() + player->mo->height) < rover->bottom.plane->ZatPoint(player->mo))
continue;
}
// Apply sector specials
- if (rover->model->special || rover->model->damage)
- P_PlayerInSpecialSector(player, rover->model);
+ P_PlayerInSpecialSector(player, rover->model);
// Apply flat specials (using the ceiling!)
P_PlayerOnSpecialFlat(
- player, TerrainTypes[rover->model->GetTexture(rover->flags & FF_INVERTSECTOR? sector_t::floor : sector_t::ceiling)]);
+ player, rover->model->GetTerrain(rover->top.isceiling));
break;
}
@@ -373,7 +372,7 @@ bool P_CheckFor3DFloorHit(AActor * mo)
if(rover->flags & FF_SOLID && rover->model->SecActTarget)
{
- if(mo->floorz == rover->top.plane->ZatPoint(mo->x, mo->y))
+ if(mo->floorz == rover->top.plane->ZatPoint(mo))
{
rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor);
return true;
@@ -403,7 +402,7 @@ bool P_CheckFor3DCeilingHit(AActor * mo)
if(rover->flags & FF_SOLID && rover->model->SecActTarget)
{
- if(mo->ceilingz == rover->bottom.plane->ZatPoint(mo->x, mo->y))
+ if(mo->ceilingz == rover->bottom.plane->ZatPoint(mo))
{
rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling);
return true;
@@ -749,7 +748,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
{
fixed_t thingbot, thingtop;
- thingbot = thing->z;
+ thingbot = thing->Z();
thingtop = thingbot + (thing->height==0? 1:thing->height);
extsector_t::xfloor *xf[2] = {&linedef->frontsector->e->XFloor, &linedef->backsector->e->XFloor};
@@ -763,6 +762,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
linedef->frontsector->floorplane.ZatPoint(x, y),
linedef->backsector->floorplane.ZatPoint(x, y) };
FTextureID highestfloorpic;
+ int highestfloorterrain = -1;
FTextureID lowestceilingpic;
highestfloorpic.SetInvalid();
@@ -789,12 +789,13 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
lowestceilingpic = *rover->bottom.texture;
}
- if(ff_top > highestfloor && delta1 < delta2 && (!restrict || thing->z >= ff_top))
+ if(ff_top > highestfloor && delta1 < delta2 && (!restrict || thing->Z() >= ff_top))
{
highestfloor = ff_top;
highestfloorpic = *rover->top.texture;
+ highestfloorterrain = rover->model->GetTerrain(rover->top.isceiling);
}
- if(ff_top > lowestfloor[j] && ff_top <= thing->z + thing->MaxStepHeight) lowestfloor[j] = ff_top;
+ if(ff_top > lowestfloor[j] && ff_top <= thing->Z() + thing->MaxStepHeight) lowestfloor[j] = ff_top;
}
}
@@ -802,6 +803,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
{
open.bottom = highestfloor;
open.floorpic = highestfloorpic;
+ open.floorterrain = highestfloorterrain;
}
if(lowestceiling < open.top)
diff --git a/src/p_3dmidtex.cpp b/src/p_3dmidtex.cpp
index 9a9492e08e..3338956f32 100644
--- a/src/p_3dmidtex.cpp
+++ b/src/p_3dmidtex.cpp
@@ -37,6 +37,7 @@
#include "templates.h"
#include "p_local.h"
+#include "p_terrain.h"
//============================================================================
@@ -275,7 +276,7 @@ bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening &
open.abovemidtex = false;
if (P_GetMidTexturePosition(linedef, 0, &tt, &tb))
{
- if (thing->z + (thing->height/2) < (tt + tb)/2)
+ if (thing->Z() + (thing->height/2) < (tt + tb)/2)
{
if (tb < open.top)
{
@@ -285,14 +286,16 @@ bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening &
}
else
{
- if (tt > open.bottom && (!restrict || thing->z >= tt))
+ if (tt > open.bottom && (!restrict || thing->Z() >= tt))
{
open.bottom = tt;
open.abovemidtex = true;
open.floorpic = linedef->sidedef[0]->GetTexture(side_t::mid);
+ open.floorterrain = TerrainTypes[open.floorpic];
+
}
// returns true if it touches the midtexture
- return (abs(thing->z - tt) <= thing->MaxStepHeight);
+ return (abs(thing->Z() - tt) <= thing->MaxStepHeight);
}
}
return false;
diff --git a/src/p_acs.cpp b/src/p_acs.cpp
index c553a1e8ad..a28c45263f 100644
--- a/src/p_acs.cpp
+++ b/src/p_acs.cpp
@@ -75,6 +75,7 @@
#include "actorptrselect.h"
#include "farchive.h"
#include "decallib.h"
+#include "p_terrain.h"
#include "version.h"
#include "g_shared/a_pickups.h"
@@ -1953,11 +1954,14 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len)
int arraynum = MapVarStore[LittleLong(chunk[2])];
if ((unsigned)arraynum < (unsigned)NumArrays)
{
- int initsize = MIN (ArrayStore[arraynum].ArraySize, (LittleLong(chunk[1])-4)/4);
+ // Use unsigned iterator here to avoid issue with GCC 4.9/5.x
+ // optimizer. Might be some undefined behavior in this code,
+ // but I don't know what it is.
+ unsigned int initsize = MIN (ArrayStore[arraynum].ArraySize, (LittleLong(chunk[1])-4)/4);
SDWORD *elems = ArrayStore[arraynum].Elements;
- for (i = 0; i < initsize; ++i)
+ for (unsigned int j = 0; j < initsize; ++j)
{
- elems[i] = LittleLong(chunk[3+i]);
+ elems[j] = LittleLong(chunk[3+j]);
}
}
chunk = (DWORD *)NextChunk((BYTE *)chunk);
@@ -3436,12 +3440,12 @@ int DLevelScript::DoSpawnSpot (int type, int spot, int tid, int angle, bool forc
while ( (aspot = iterator.Next ()) )
{
- spawned += DoSpawn (type, aspot->x, aspot->y, aspot->z, tid, angle, force);
+ spawned += DoSpawn (type, aspot->X(), aspot->Y(), aspot->Z(), tid, angle, force);
}
}
else if (activator != NULL)
{
- spawned += DoSpawn (type, activator->x, activator->y, activator->z, tid, angle, force);
+ spawned += DoSpawn (type, activator->X(), activator->Y(), activator->Z(), tid, angle, force);
}
return spawned;
}
@@ -3457,12 +3461,12 @@ int DLevelScript::DoSpawnSpotFacing (int type, int spot, int tid, bool force)
while ( (aspot = iterator.Next ()) )
{
- spawned += DoSpawn (type, aspot->x, aspot->y, aspot->z, tid, aspot->angle >> 24, force);
+ spawned += DoSpawn (type, aspot->X(), aspot->Y(), aspot->Z(), tid, aspot->angle >> 24, force);
}
}
else if (activator != NULL)
{
- spawned += DoSpawn (type, activator->x, activator->y, activator->z, tid, activator->angle >> 24, force);
+ spawned += DoSpawn (type, activator->X(), activator->Y(), activator->Z(), tid, activator->angle >> 24, force);
}
return spawned;
}
@@ -4140,7 +4144,7 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b
F3DFloor *ff = sec->e->XFloor.ffloors[i];
if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) &&
- actor->z >= ff->top.plane->ZatPoint(actor->x, actor->y))
+ actor->Z() >= ff->top.plane->ZatPoint(actor))
{ // This floor is beneath our feet.
secpic = *ff->top.texture;
break;
@@ -4153,14 +4157,14 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b
}
else
{
- fixed_t z = actor->z + actor->height;
+ fixed_t z = actor->Z() + actor->height;
// Looking through planes from bottom to top
for (i = numff-1; i >= 0; --i)
{
F3DFloor *ff = sec->e->XFloor.ffloors[i];
if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) &&
- z <= ff->bottom.plane->ZatPoint(actor->x, actor->y))
+ z <= ff->bottom.plane->ZatPoint(actor))
{ // This floor is above our eyes.
secpic = *ff->bottom.texture;
break;
@@ -4457,6 +4461,8 @@ enum EACSFunctions
ACSF_QuakeEx,
ACSF_Warp, // 92
ACSF_GetMaxInventory,
+ ACSF_SetSectorDamage,
+ ACSF_SetSectorTerrain,
/* Zandronum's - these must be skipped when we reach 99!
-100:ResetMap(0),
@@ -4714,8 +4720,8 @@ static bool DoSpawnDecal(AActor *actor, const FDecalTemplate *tpl, int flags, an
{
angle += actor->angle;
}
- return NULL != ShootDecal(tpl, actor, actor->Sector, actor->x, actor->y,
- actor->z + (actor->height>>1) - actor->floorclip + actor->GetBobOffset() + zofs,
+ return NULL != ShootDecal(tpl, actor, actor->Sector, actor->X(), actor->Y(),
+ actor->Z() + (actor->height>>1) - actor->floorclip + actor->GetBobOffset() + zofs,
angle, distance, !!(flags & SDF_PERMANENT));
}
@@ -5389,6 +5395,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const
FName damagetype = argCount > 5 && args[5]? FName(FBehavior::StaticLookupString(args[5])) : NAME_None;
fixed_t range = argCount > 6 && args[6]? args[6] : MISSILERANGE;
int flags = argCount > 7 && args[7]? args[7] : 0;
+ int pufftid = argCount > 8 && args[8]? args[8] : 0;
int fhflags = 0;
if (flags & FHF_NORANDOMPUFFZ) fhflags |= LAF_NORANDOMPUFFZ;
@@ -5396,7 +5403,12 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const
if (args[0] == 0)
{
- P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype, fhflags);
+ AActor *puff = P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype, fhflags);
+ if (puff != NULL && pufftid != 0)
+ {
+ puff->tid = pufftid;
+ puff->AddToHash();
+ }
}
else
{
@@ -5405,7 +5417,12 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const
while ((source = it.Next()) != NULL)
{
- P_LineAttack(source, angle, range, pitch, damage, damagetype, pufftype, fhflags);
+ AActor *puff = P_LineAttack(source, angle, range, pitch, damage, damagetype, pufftype, fhflags);
+ if (puff != NULL && pufftid != 0)
+ {
+ puff->tid = pufftid;
+ puff->AddToHash();
+ }
}
}
}
@@ -5931,6 +5948,39 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
break;
+ case ACSF_SetSectorDamage:
+ if (argCount >= 2)
+ {
+ FSectorTagIterator it(args[0]);
+ int s;
+ while ((s = it.Next()) >= 0)
+ {
+ sector_t *sec = §ors[s];
+
+ sec->damageamount = args[1];
+ sec->damagetype = argCount >= 3 ? FName(FBehavior::StaticLookupString(args[2])) : FName(NAME_None);
+ sec->damageinterval = argCount >= 4 ? clamp(args[3], 1, INT_MAX) : 32;
+ sec->leakydamage = argCount >= 5 ? args[4] : 0;
+ }
+ }
+ break;
+
+ case ACSF_SetSectorTerrain:
+ if (argCount >= 3)
+ {
+ if (args[1] == sector_t::floor || args[1] == sector_t::ceiling)
+ {
+ int terrain = P_FindTerrain(FBehavior::StaticLookupString(args[2]));
+ FSectorTagIterator it(args[0]);
+ int s;
+ while ((s = it.Next()) >= 0)
+ {
+ sectors[s].terrainnum[args[1]] = terrain;
+ }
+ }
+ }
+ break;
+
default:
break;
}
@@ -8540,11 +8590,11 @@ scriptwait:
}
else if (pcd == PCD_GETACTORZ)
{
- STACK(1) = actor->z + actor->GetBobOffset();
+ STACK(1) = actor->Z() + actor->GetBobOffset();
}
else
{
- STACK(1) = (&actor->x)[pcd - PCD_GETACTORX];
+ STACK(1) = pcd == PCD_GETACTORX ? actor->X() : pcd == PCD_GETACTORY ? actor->Y() : actor->Z();
}
}
break;
diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp
index e94beedf6b..a7a26e9c82 100644
--- a/src/p_buildmap.cpp
+++ b/src/p_buildmap.cpp
@@ -443,6 +443,7 @@ static void LoadSectors (sectortype *bsec)
sec->movefactor = ORIG_FRICTION_FACTOR;
sec->ColorMap = map;
sec->ZoneNumber = 0xFFFF;
+ sec->terrainnum[sector_t::ceiling] = sec->terrainnum[sector_t::floor] = -1;
if (bsec->floorstat & 4)
{
diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp
index 7efef80a53..3203cf7779 100644
--- a/src/p_ceiling.cpp
+++ b/src/p_ceiling.cpp
@@ -90,6 +90,7 @@ void DCeiling::Serialize (FArchive &arc)
void DCeiling::PlayCeilingSound ()
{
+ if (m_Sector->Flags & SECF_SILENTMOVE) return;
if (m_Sector->seqType >= 0)
{
SN_StartSequence (m_Sector, CHAN_CEILING, m_Sector->seqType, SEQ_PLATFORM, 0, false);
@@ -142,7 +143,7 @@ void DCeiling::Tick ()
// movers with texture change, change the texture then get removed
case genCeilingChgT:
case genCeilingChg0:
- m_Sector->special = m_NewSpecial;
+ m_Sector->SetSpecial(&m_NewSpecial);
// fall through
case genCeilingChg:
m_Sector->SetTexture(sector_t::ceiling, m_Texture);
@@ -175,7 +176,7 @@ void DCeiling::Tick ()
// then remove the active ceiling
case genCeilingChgT:
case genCeilingChg0:
- m_Sector->special = m_NewSpecial;
+ m_Sector->SetSpecial(&m_NewSpecial);
// fall through
case genCeilingChg:
m_Sector->SetTexture(sector_t::ceiling, m_Texture);
@@ -435,11 +436,11 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line,
switch (change & 3)
{
case 1: // type is zeroed
- ceiling->m_NewSpecial = 0;
+ ceiling->m_NewSpecial.Clear();
ceiling->m_Type = genCeilingChg0;
break;
case 2: // type is copied
- ceiling->m_NewSpecial = sec->special;
+ sec->GetSpecial(&ceiling->m_NewSpecial);
ceiling->m_Type = genCeilingChgT;
break;
case 3: // type is left alone
@@ -454,11 +455,11 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line,
switch (change & 3)
{
case 1: // type is zeroed
- ceiling->m_NewSpecial = 0;
+ ceiling->m_NewSpecial.Clear();
ceiling->m_Type = genCeilingChg0;
break;
case 2: // type is copied
- ceiling->m_NewSpecial = line->frontsector->special;
+ line->frontsector->GetSpecial(&ceiling->m_NewSpecial);
ceiling->m_Type = genCeilingChgT;
break;
case 3: // type is left alone
diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp
index 13efb2643b..d9785a3f20 100644
--- a/src/p_conversation.cpp
+++ b/src/p_conversation.cpp
@@ -1117,7 +1117,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
if (facetalker)
{
A_FaceTarget (npc);
- pc->angle = R_PointToAngle2 (pc->x, pc->y, npc->x, npc->y);
+ pc->angle = pc->AngleTo(npc);
}
if ((npc->flags & MF_FRIENDLY) || (npc->flags4 & MF4_NOHATEPLAYERS))
{
@@ -1345,12 +1345,14 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
if (reply->NextNode != 0)
{
int rootnode = npc->ConversationRoot;
- if (reply->NextNode < 0)
+ unsigned next = (unsigned)(rootnode + (reply->NextNode < 0 ? -1 : 1) * reply->NextNode - 1);
+
+ if (next < StrifeDialogues.Size())
{
- unsigned next = (unsigned)(rootnode - reply->NextNode - 1);
- if (gameaction != ga_slideshow && next < StrifeDialogues.Size())
+ npc->Conversation = StrifeDialogues[next];
+
+ if (gameaction != ga_slideshow)
{
- npc->Conversation = StrifeDialogues[next];
P_StartConversation (npc, player->mo, player->ConversationFaceTalker, false);
return;
}
@@ -1359,10 +1361,6 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
S_StopSound (npc, CHAN_VOICE);
}
}
- else
- {
- npc->Conversation = StrifeDialogues[rootnode + reply->NextNode - 1];
- }
}
npc->angle = player->ConversationNPCAngle;
diff --git a/src/p_doors.cpp b/src/p_doors.cpp
index 49ed20f460..bce3249024 100644
--- a/src/p_doors.cpp
+++ b/src/p_doors.cpp
@@ -250,6 +250,8 @@ void DDoor::DoorSound(bool raise, DSeqNode *curseq) const
choice = !raise;
+ if (m_Sector->Flags & SECF_SILENTMOVE) return;
+
if (m_Speed >= FRACUNIT*8)
{
choice += 2;
@@ -511,8 +513,6 @@ void P_SpawnDoorCloseIn30 (sector_t *sec)
fixed_t height;
DDoor *door = new DDoor (sec);
- sec->special = 0;
-
door->m_Sector = sec;
door->m_Direction = 0;
door->m_Type = DDoor::doorRaise;
@@ -533,7 +533,6 @@ void P_SpawnDoorCloseIn30 (sector_t *sec)
void P_SpawnDoorRaiseIn5Mins (sector_t *sec)
{
- sec->special = 0;
new DDoor (sec, DDoor::doorRaiseIn5Mins, 2*FRACUNIT, TICRATE*30/7, 0);
}
diff --git a/src/p_effect.cpp b/src/p_effect.cpp
index 9450add4d0..08604fac3f 100644
--- a/src/p_effect.cpp
+++ b/src/p_effect.cpp
@@ -356,9 +356,10 @@ static void MakeFountain (AActor *actor, int color1, int color2)
angle_t an = M_Random()<<(24-ANGLETOFINESHIFT);
fixed_t out = FixedMul (actor->radius, M_Random()<<8);
- particle->x = actor->x + FixedMul (out, finecosine[an]);
- particle->y = actor->y + FixedMul (out, finesine[an]);
- particle->z = actor->z + actor->height + FRACUNIT;
+ fixedvec3 pos = actor->Vec3Offset(FixedMul(out, finecosine[an]), FixedMul(out, finesine[an]), actor->height + FRACUNIT);
+ particle->x = pos.x;
+ particle->y = pos.y;
+ particle->z = pos.z;
if (out < actor->radius/8)
particle->velz += FRACUNIT*10/3;
else
@@ -395,9 +396,10 @@ void P_RunEffect (AActor *actor, int effects)
{
// Rocket trail
- fixed_t backx = actor->x - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2);
- fixed_t backy = actor->y - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2);
- fixed_t backz = actor->z - (actor->height>>3) * (actor->velz>>16) + (2*actor->height)/3;
+
+ fixed_t backx = - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2);
+ fixed_t backy = - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2);
+ fixed_t backz = - (actor->height>>3) * (actor->velz>>16) + (2*actor->height)/3;
angle_t an = (moveangle + ANG90) >> ANGLETOFINESHIFT;
int speed;
@@ -405,9 +407,13 @@ void P_RunEffect (AActor *actor, int effects)
particle = JitterParticle (3 + (M_Random() & 31));
if (particle) {
fixed_t pathdist = M_Random()<<8;
- particle->x = backx - FixedMul(actor->velx, pathdist);
- particle->y = backy - FixedMul(actor->vely, pathdist);
- particle->z = backz - FixedMul(actor->velz, pathdist);
+ fixedvec3 pos = actor->Vec3Offset(
+ backx - FixedMul(actor->velx, pathdist),
+ backy - FixedMul(actor->vely, pathdist),
+ backz - FixedMul(actor->velz, pathdist));
+ particle->x = pos.x;
+ particle->y = pos.y;
+ particle->z = pos.z;
speed = (M_Random () - 128) * (FRACUNIT/200);
particle->velx += FixedMul (speed, finecosine[an]);
particle->vely += FixedMul (speed, finesine[an]);
@@ -420,9 +426,13 @@ void P_RunEffect (AActor *actor, int effects)
particle_t *particle = JitterParticle (3 + (M_Random() & 31));
if (particle) {
fixed_t pathdist = M_Random()<<8;
- particle->x = backx - FixedMul(actor->velx, pathdist);
- particle->y = backy - FixedMul(actor->vely, pathdist);
- particle->z = backz - FixedMul(actor->velz, pathdist) + (M_Random() << 10);
+ fixedvec3 pos = actor->Vec3Offset(
+ backx - FixedMul(actor->velx, pathdist),
+ backy - FixedMul(actor->vely, pathdist),
+ backz - FixedMul(actor->velz, pathdist) + (M_Random() << 10));
+ particle->x = pos.x;
+ particle->y = pos.y;
+ particle->z = pos.z;
speed = (M_Random () - 128) * (FRACUNIT/200);
particle->velx += FixedMul (speed, finecosine[an]);
particle->vely += FixedMul (speed, finesine[an]);
@@ -441,10 +451,12 @@ void P_RunEffect (AActor *actor, int effects)
{
// Grenade trail
- P_DrawSplash2 (6,
- actor->x - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2),
- actor->y - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2),
- actor->z - (actor->height>>3) * (actor->velz>>16) + (2*actor->height)/3,
+ fixedvec3 pos = actor->Vec3Offset(
+ -FixedMul(finecosine[(moveangle) >> ANGLETOFINESHIFT], actor->radius * 2),
+ -FixedMul(finesine[(moveangle) >> ANGLETOFINESHIFT], actor->radius * 2),
+ -(actor->height >> 3) * (actor->velz >> 16) + (2 * actor->height) / 3);
+
+ P_DrawSplash2 (6, pos.x, pos.y, pos.z,
moveangle + ANG180, 2, 2);
}
if (effects & FX_FOUNTAINMASK)
@@ -476,10 +488,11 @@ void P_RunEffect (AActor *actor, int effects)
if (particle != NULL)
{
angle_t ang = M_Random () << (32-ANGLETOFINESHIFT-8);
- particle->x = actor->x + FixedMul (actor->radius, finecosine[ang]);
- particle->y = actor->y + FixedMul (actor->radius, finesine[ang]);
+ fixedvec3 pos = actor->Vec3Offset(FixedMul (actor->radius, finecosine[ang]), FixedMul (actor->radius, finesine[ang]), 0);
+ particle->x = pos.x;
+ particle->y = pos.y;
+ particle->z = pos.z;
particle->color = *protectColors[M_Random() & 1];
- particle->z = actor->z;
particle->velz = FRACUNIT;
particle->accz = M_Random () << 7;
particle->size = 1;
@@ -620,8 +633,8 @@ void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVecto
double r;
double dirz;
- if (abs(mo->x - FLOAT2FIXED(start.X)) < 20 * FRACUNIT
- && (mo->y - FLOAT2FIXED(start.Y)) < 20 * FRACUNIT)
+ if (abs(mo->X() - FLOAT2FIXED(start.X)) < 20 * FRACUNIT
+ && (mo->Y() - FLOAT2FIXED(start.Y)) < 20 * FRACUNIT)
{ // This player (probably) fired the railgun
S_Sound (mo, CHAN_WEAPON, sound, 1, ATTN_NORM);
}
@@ -631,7 +644,7 @@ void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVecto
// Only consider sound in 2D (for now, anyway)
// [BB] You have to divide by lengthsquared here, not multiply with it.
- r = ((start.Y - FIXED2DBL(mo->y)) * (-dir.Y) - (start.X - FIXED2DBL(mo->x)) * (dir.X)) / lengthsquared;
+ r = ((start.Y - FIXED2DBL(mo->Y())) * (-dir.Y) - (start.X - FIXED2DBL(mo->X())) * (dir.X)) / lengthsquared;
r = clamp(r, 0., 1.);
dirz = dir.Z;
@@ -833,9 +846,13 @@ void P_DisconnectEffect (AActor *actor)
if (!p)
break;
- p->x = actor->x + ((M_Random()-128)<<9) * (actor->radius>>FRACBITS);
- p->y = actor->y + ((M_Random()-128)<<9) * (actor->radius>>FRACBITS);
- p->z = actor->z + (M_Random()<<8) * (actor->height>>FRACBITS);
+ fixedvec3 pos = actor->Vec3Offset(
+ ((M_Random()-128)<<9) * (actor->radius>>FRACBITS),
+ ((M_Random()-128)<<9) * (actor->radius>>FRACBITS),
+ (M_Random()<<8) * (actor->height>>FRACBITS));
+ p->x = pos.x;
+ p->y = pos.y;
+ p->z = pos.z;
p->accz -= FRACUNIT/4096;
p->color = M_Random() < 128 ? maroon1 : maroon2;
p->size = 4;
diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp
index 9b84244323..28a81e9108 100644
--- a/src/p_enemy.cpp
+++ b/src/p_enemy.cpp
@@ -138,7 +138,7 @@ void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soun
for (actor = sec->thinglist; actor != NULL; actor = actor->snext)
{
if (actor != soundtarget && (!splash || !(actor->flags4 & MF4_NOSPLASHALERT)) &&
- (!maxdist || (P_AproxDistance(actor->x - emitter->x, actor->y - emitter->y) <= maxdist)))
+ (!maxdist || (actor->AproxDistance(emitter) <= maxdist)))
{
actor->LastHeard = soundtarget;
}
@@ -231,7 +231,7 @@ bool AActor::CheckMeleeRange ()
if (!pl)
return false;
- dist = P_AproxDistance (pl->x - x, pl->y - y);
+ dist = AproxDistance (pl);
if (dist >= meleerange + pl->radius)
return false;
@@ -243,9 +243,9 @@ bool AActor::CheckMeleeRange ()
// [RH] Don't melee things too far above or below actor.
if (!(flags5 & MF5_NOVERTICALMELEERANGE))
{
- if (pl->z > z + height)
+ if (pl->Z() > z + height)
return false;
- if (pl->z + pl->height < z)
+ if (pl->Z() + pl->height < z)
return false;
}
@@ -275,16 +275,16 @@ bool P_CheckMeleeRange2 (AActor *actor)
return false;
}
mo = actor->target;
- dist = P_AproxDistance (mo->x-actor->x, mo->y-actor->y);
+ dist = mo->AproxDistance (actor);
if (dist >= MELEERANGE*2 || dist < MELEERANGE-20*FRACUNIT + mo->radius)
{
return false;
}
- if (mo->z > actor->z+actor->height)
+ if (mo->Z() > actor->Z()+actor->height)
{ // Target is higher than the attacker
return false;
}
- else if (actor->z > mo->z+mo->height)
+ else if (actor->Z() > mo->Z()+mo->height)
{ // Attacker is higher
return false;
}
@@ -348,8 +348,7 @@ bool P_CheckMissileRange (AActor *actor)
// OPTIMIZE: get this from a global checksight
// [RH] What?
- dist = P_AproxDistance (actor->x-actor->target->x,
- actor->y-actor->target->y) - 64*FRACUNIT;
+ dist = actor->AproxDistance (actor->target) - 64*FRACUNIT;
if (actor->MeleeState == NULL)
dist -= 128*FRACUNIT; // no melee attack, so fire more
@@ -393,8 +392,8 @@ bool P_HitFriend(AActor * self)
if (self->flags&MF_FRIENDLY && self->target != NULL)
{
- angle_t angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y);
- fixed_t dist = P_AproxDistance (self->x - self->target->x, self->y - self->target->y);
+ angle_t angle = self->AngleTo(self->target);
+ fixed_t dist = self->AproxDistance (self->target);
P_AimLineAttack (self, angle, dist, &linetarget, 0, true);
if (linetarget != NULL && linetarget != self->target)
{
@@ -435,7 +434,7 @@ bool P_Move (AActor *actor)
// it difficult to thrust them vertically in a reasonable manner.
// [GZ] Let jumping actors jump.
if (!((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP))
- && actor->z > actor->floorz && !(actor->flags2 & MF2_ONMOBJ))
+ && actor->Z() > actor->floorz && !(actor->flags2 & MF2_ONMOBJ))
{
return false;
}
@@ -450,7 +449,7 @@ bool P_Move (AActor *actor)
if ((actor->flags6 & MF6_JUMPDOWN) && target &&
!(target->IsFriend(actor)) &&
- P_AproxDistance(actor->x - target->x, actor->y - target->y) < FRACUNIT*144 &&
+ actor->AproxDistance(target) < FRACUNIT*144 &&
pr_dropoff() < 235)
{
dropoff = 2;
@@ -539,11 +538,11 @@ bool P_Move (AActor *actor)
// actually walking down a step.
if (try_ok &&
!((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP))
- && actor->z > actor->floorz && !(actor->flags2 & MF2_ONMOBJ))
+ && actor->Z() > actor->floorz && !(actor->flags2 & MF2_ONMOBJ))
{
- if (actor->z <= actor->floorz + actor->MaxStepHeight)
+ if (actor->Y() <= actor->floorz + actor->MaxStepHeight)
{
- fixed_t savedz = actor->z;
+ fixed_t savedz = actor->Z();
actor->z = actor->floorz;
// Make sure that there isn't some other actor between us and
// the floor we could get stuck in. The old code did not do this.
@@ -554,7 +553,7 @@ bool P_Move (AActor *actor)
else
{ // The monster just hit the floor, so trigger any actions.
if (actor->floorsector->SecActTarget != NULL &&
- actor->floorz == actor->floorsector->floorplane.ZatPoint(actor->x, actor->y))
+ actor->floorz == actor->floorsector->floorplane.ZatPoint(actor))
{
actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor);
}
@@ -567,7 +566,7 @@ bool P_Move (AActor *actor)
{
if (((actor->flags6 & MF6_CANJUMP)||(actor->flags & MF_FLOAT)) && tm.floatok)
{ // must adjust height
- fixed_t savedz = actor->z;
+ fixed_t savedz = actor->Z();
if (actor->z < tm.floorz)
actor->z += actor->FloatSpeed;
@@ -848,11 +847,11 @@ void P_NewChaseDir(AActor * actor)
// Try to move away from a dropoff
if (actor->floorz - actor->dropoffz > actor->MaxDropOffHeight &&
- actor->z <= actor->floorz && !(actor->flags & MF_DROPOFF) &&
+ actor->Z() <= actor->floorz && !(actor->flags & MF_DROPOFF) &&
!(actor->flags2 & MF2_ONMOBJ) &&
!(actor->flags & MF_FLOAT) && !(i_compatflags & COMPATF_DROPOFF))
{
- FBoundingBox box(actor->x, actor->y, actor->radius);
+ FBoundingBox box(actor->X(), actor->Y(), actor->radius);
FBlockLinesIterator it(box);
line_t *line;
@@ -867,14 +866,14 @@ void P_NewChaseDir(AActor * actor)
box.Bottom() < line->bbox[BOXTOP] &&
box.BoxOnLineSide(line) == -1)
{
- fixed_t front = line->frontsector->floorplane.ZatPoint(actor->x,actor->y);
- fixed_t back = line->backsector->floorplane.ZatPoint(actor->x,actor->y);
+ fixed_t front = line->frontsector->floorplane.ZatPoint(actor);
+ fixed_t back = line->backsector->floorplane.ZatPoint(actor);
angle_t angle;
// The monster must contact one of the two floors,
// and the other must be a tall dropoff.
- if (back == actor->z && front < actor->z - actor->MaxDropOffHeight)
+ if (back == actor->Z() && front < actor->Z() - actor->MaxDropOffHeight)
{
angle = R_PointToAngle2(0,0,line->dx,line->dy); // front side dropoff
}
@@ -933,7 +932,7 @@ void P_NewChaseDir(AActor * actor)
if (actor->flags3 & MF3_AVOIDMELEE)
{
bool ismeleeattacker = false;
- fixed_t dist = P_AproxDistance(actor->x-target->x, actor->y-target->y);
+ fixed_t dist = actor->AproxDistance(target);
if (target->player == NULL)
{
ismeleeattacker = (target->MissileState == NULL && dist < (target->meleerange + target->radius)*2);
@@ -1151,7 +1150,7 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams
fov = allaround ? 0 : ANGLE_180;
}
- fixed_t dist = P_AproxDistance (other->x - lookee->x, other->y - lookee->y);
+ fixed_t dist = lookee->AproxDistance (other);
if (maxdist && dist > maxdist)
return false; // [KS] too far
@@ -1161,7 +1160,7 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams
if (fov && fov < ANGLE_MAX)
{
- angle_t an = R_PointToAngle2 (lookee->x, lookee->y, other->x, other->y) - lookee->angle;
+ angle_t an = lookee->AngleTo(other) - lookee->angle;
if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2)))
{
@@ -1202,8 +1201,7 @@ bool P_LookForMonsters (AActor *actor)
{ // Not a valid monster
continue;
}
- if (P_AproxDistance (actor->x-mo->x, actor->y-mo->y)
- > MONS_LOOK_RANGE)
+ if (mo->AproxDistance (actor) > MONS_LOOK_RANGE)
{ // Out of range
continue;
}
@@ -1703,10 +1701,8 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params)
if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) ||
player->mo->flags3 & MF3_GHOST)
{
- if ((P_AproxDistance (player->mo->x - actor->x,
- player->mo->y - actor->y) > 2*MELEERANGE)
- && P_AproxDistance (player->mo->velx, player->mo->vely)
- < 5*FRACUNIT)
+ if ((player->mo->AproxDistance (actor) > 2*MELEERANGE)
+ && P_AproxDistance (player->mo->velx, player->mo->vely) < 5*FRACUNIT)
{ // Player is sneaking - can't detect
continue;
}
@@ -1908,7 +1904,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx)
}
else
{
- dist = P_AproxDistance (targ->x - self->x, targ->y - self->y);
+ dist = self->AproxDistance (targ);
// [KS] If the target is too far away, don't respond to the sound.
if (maxheardist && dist > maxheardist)
@@ -1979,7 +1975,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx)
{
if (self->flags & MF_AMBUSH)
{
- dist = P_AproxDistance (self->target->x - self->x, self->target->y - self->y);
+ dist = self->AproxDistance (self->target);
if (P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING) &&
(!minseedist || dist > minseedist) &&
(!maxseedist || dist < maxseedist))
@@ -2402,12 +2398,12 @@ void A_DoChase (VMFrameStack *stack, AActor *actor, bool fastchase, FState *mele
actor->FastChaseStrafeCount = 0;
actor->velx = 0;
actor->vely = 0;
- fixed_t dist = P_AproxDistance (actor->x - actor->target->x, actor->y - actor->target->y);
+ fixed_t dist = actor->AproxDistance (actor->target);
if (dist < CLASS_BOSS_STRAFE_RANGE)
{
if (pr_chase() < 100)
{
- angle_t ang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+ angle_t ang = actor->AngleTo(actor->target);
if (pr_chase() < 128) ang += ANGLE_90;
else ang -= ANGLE_90;
actor->velx = 13 * finecosine[ang>>ANGLETOFINESHIFT];
@@ -2569,11 +2565,11 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
if (testsec)
{
fixed_t zdist1, zdist2;
- if (P_Find3DFloor(testsec, corpsehit->x, corpsehit->y, corpsehit->z, false, true, zdist1)
- != P_Find3DFloor(testsec, self->x, self->y, self->z, false, true, zdist2))
+ if (P_Find3DFloor(testsec, corpsehit->X(), corpsehit->Y(), corpsehit->Z(), false, true, zdist1)
+ != P_Find3DFloor(testsec, self->X(), self->Y(), self->Z(), false, true, zdist2))
{
// Not on same floor
- if (vilesec == corpsec || abs(zdist1 - self->z) > self->height)
+ if (vilesec == corpsec || abs(zdist1 - self->Z()) > self->height)
continue;
}
}
@@ -2587,7 +2583,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
corpsehit->flags |= MF_SOLID;
corpsehit->height = corpsehit->GetDefault()->height;
- bool check = P_CheckPosition(corpsehit, corpsehit->x, corpsehit->y);
+ bool check = P_CheckPosition(corpsehit, corpsehit->X(), corpsehit->Y());
corpsehit->flags = oldflags;
corpsehit->radius = oldradius;
corpsehit->height = oldheight;
@@ -2770,7 +2766,7 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch, a
self->flags &= ~MF_AMBUSH;
- angle_t other_angle = R_PointToAngle2 (self->x, self->y, other->x, other->y);
+ angle_t other_angle = self->AngleTo(other);
// 0 means no limit. Also, if we turn in a single step anyways, no need to go through the algorithms.
// It also means that there is no need to check for going past the other.
@@ -2819,19 +2815,19 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch, a
// If the target z is above the target's head, reposition to the middle of
// its body.
- if (target_z >= other->z + other->height)
+ if (target_z >= other->Z() + other->height)
{
- target_z = other->z + (other->height / 2);
+ target_z = other->Z() + (other->height / 2);
}
//Note there is no +32*FRACUNIT on purpose. This is for customization sake.
//If one doesn't want this behavior, just don't use FAF_BOTTOM.
if (flags & FAF_BOTTOM)
- target_z = other->z + other->GetBobOffset();
+ target_z = other->Z() + other->GetBobOffset();
if (flags & FAF_MIDDLE)
- target_z = other->z + (other->height / 2) + other->GetBobOffset();
+ target_z = other->Z() + (other->height / 2) + other->GetBobOffset();
if (flags & FAF_TOP)
- target_z = other->z + (other->height) + other->GetBobOffset();
+ target_z = other->Z() + (other->height) + other->GetBobOffset();
if (!(flags & FAF_NODISTFACTOR))
target_z += pitch_offset;
@@ -2948,10 +2944,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail)
self->flags &= ~MF_AMBUSH;
- self->angle = R_PointToAngle2 (self->x,
- self->y,
- self->target->x,
- self->target->y);
+ self->angle = self->AngleTo(self->target);
self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, self->target);
if (linetarget == NULL)
@@ -2964,10 +2957,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail)
}
// Let the aim trail behind the player
- self->angle = R_PointToAngle2 (self->x,
- self->y,
- self->target->x - self->target->velx * 3,
- self->target->y - self->target->vely * 3);
+ self->angle = self->AngleTo(self->target, -self->target->velx * 3, -self->target->vely * 3);
if (self->target->flags & MF_SHADOW && !(self->flags6 & MF6_SEEINVISIBLE))
{
@@ -3126,7 +3116,7 @@ AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int c
AActor *mo;
fixed_t spawnz;
- spawnz = source->z;
+ spawnz = source->Z();
if (!(i_compatflags & COMPATF_NOTOSSDROPS))
{
int style = sv_dropstyle;
@@ -3143,7 +3133,7 @@ AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int c
spawnz += source->height / 2;
}
}
- mo = Spawn(type, source->x, source->y, spawnz, ALLOW_REPLACE);
+ mo = Spawn(type, source->X(), source->Y(), spawnz, ALLOW_REPLACE);
if (mo != NULL)
{
mo->flags |= MF_DROPPED;
diff --git a/src/p_floor.cpp b/src/p_floor.cpp
index 9e78060391..e3763e677a 100644
--- a/src/p_floor.cpp
+++ b/src/p_floor.cpp
@@ -55,6 +55,8 @@ inline FArchive &operator<< (FArchive &arc, DFloor::EFloor &type)
static void StartFloorSound (sector_t *sec)
{
+ if (sec->Flags & SECF_SILENTMOVE) return;
+
if (sec->seqType >= 0)
{
SN_StartSequence (sec, CHAN_FLOOR, sec->seqType, SEQ_PLATFORM, 0);
@@ -159,7 +161,7 @@ void DFloor::Tick ()
case donutRaise:
case genFloorChgT:
case genFloorChg0:
- m_Sector->special = (m_Sector->special & SECRET_MASK) | m_NewSpecial;
+ m_Sector->SetSpecial(&m_NewSpecial);
//fall thru
case genFloorChg:
m_Sector->SetTexture(sector_t::floor, m_Texture);
@@ -175,7 +177,7 @@ void DFloor::Tick ()
case floorLowerAndChange:
case genFloorChgT:
case genFloorChg0:
- m_Sector->special = (m_Sector->special & SECRET_MASK) | m_NewSpecial;
+ m_Sector->SetSpecial(&m_NewSpecial);
//fall thru
case genFloorChg:
m_Sector->SetTexture(sector_t::floor, m_Texture);
@@ -233,14 +235,14 @@ void DFloor::SetFloorChangeType (sector_t *sec, int change)
switch (change & 3)
{
case 1:
- m_NewSpecial = 0;
+ m_NewSpecial.Clear();
m_Type = DFloor::genFloorChg0;
break;
case 2:
m_Type = DFloor::genFloorChg;
break;
case 3:
- m_NewSpecial = sec->special & ~SECRET_MASK;
+ sec->GetSpecial(&m_NewSpecial);
m_Type = DFloor::genFloorChgT;
break;
}
@@ -438,11 +440,11 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag,
{
FTextureID oldpic = sec->GetTexture(sector_t::floor);
sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor));
- sec->special = (sec->special & SECRET_MASK) | (line->frontsector->special & ~SECRET_MASK);
+ sec->TransferSpecial(line->frontsector);
}
else
{
- sec->special &= SECRET_MASK;
+ sec->ClearSpecial();
}
break;
@@ -453,8 +455,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag,
floor->m_Texture = sec->GetTexture(sector_t::floor);
// jff 1/24/98 make sure floor->m_NewSpecial gets initialized
// in case no surrounding sector is at floordestheight
- // --> should not affect compatibility <--
- floor->m_NewSpecial = sec->special & ~SECRET_MASK;
+ sec->GetSpecial(&floor->m_NewSpecial);
//jff 5/23/98 use model subroutine to unify fixes and handling
sector_t *modelsec;
@@ -462,7 +463,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag,
if (modelsec != NULL)
{
floor->m_Texture = modelsec->GetTexture(sector_t::floor);
- floor->m_NewSpecial = modelsec->special & ~SECRET_MASK;
+ modelsec->GetSpecial(&floor->m_NewSpecial);
}
break;
@@ -635,7 +636,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
{
// [RH] Find the next sector by scanning for Stairs_Special?
tsec = sec->NextSpecialSector (
- (sec->special & 0xff) == Stairs_Special1 ?
+ sec->special == Stairs_Special1 ?
Stairs_Special2 : Stairs_Special1, prev);
if ( (ok = (tsec != NULL)) )
@@ -792,7 +793,7 @@ bool EV_DoDonut (int tag, line_t *line, fixed_t pillarspeed, fixed_t slimespeed)
floor->m_Sector = s2;
floor->m_Speed = slimespeed;
floor->m_Texture = s3->GetTexture(sector_t::floor);
- floor->m_NewSpecial = 0;
+ floor->m_NewSpecial.Clear();
height = s3->FindHighestFloorPoint (&spot);
floor->m_FloorDestDist = s2->floorplane.PointToDist (spot, height);
floor->StartFloorSound ();
@@ -1091,7 +1092,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag)
if (line)
{ // [RH] if no line, no change
sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor));
- sec->special = (sec->special & SECRET_MASK) | (line->frontsector->special & ~SECRET_MASK);
+ sec->TransferSpecial(line->frontsector);
}
break;
case numChangeOnly:
@@ -1099,7 +1100,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag)
if (secm)
{ // if no model, no change
sec->SetTexture(sector_t::floor, secm->GetTexture(sector_t::floor));
- sec->special = secm->special;
+ sec->TransferSpecial(secm);
}
break;
default:
diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp
index fa0df283cc..b97d17af87 100644
--- a/src/p_interaction.cpp
+++ b/src/p_interaction.cpp
@@ -84,7 +84,7 @@ FName MeansOfDeath;
//
void P_TouchSpecialThing (AActor *special, AActor *toucher)
{
- fixed_t delta = special->z - toucher->z;
+ fixed_t delta = special->Z() - toucher->Z();
// The pickup is at or above the toucher's feet OR
// The pickup is below the toucher.
@@ -1040,7 +1040,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
return -1;
}
- if ((rawdamage < TELEFRAG_DAMAGE) || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with NOTELEFRAGPIERCE or it may not guarantee its effect.
+ if ((rawdamage < TELEFRAG_DAMAGE) || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with LAXTELEFRAGDMG or it may not guarantee its effect.
{
if (player && damage > 1)
{
@@ -1153,13 +1153,13 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
// If the origin and target are in exactly the same spot, choose a random direction.
// (Most likely cause is from telefragging somebody during spawning because they
// haven't moved from their spawn spot at all.)
- if (origin->x == target->x && origin->y == target->y)
+ if (origin->X() == target->X() && origin->Y() == target->Y())
{
ang = pr_kickbackdir.GenRand32();
}
else
{
- ang = R_PointToAngle2 (origin->x, origin->y, target->x, target->y);
+ ang = origin->AngleTo(target);
}
// Calculate this as float to avoid overflows so that the
@@ -1179,7 +1179,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
// make fall forwards sometimes
if ((damage < 40) && (damage > target->health)
- && (target->z - origin->z > 64*FRACUNIT)
+ && (target->Z() - origin->Z() > 64*FRACUNIT)
&& (pr_damagemobj()&1)
// [RH] But only if not too fast and not flying
&& thrust < 10*FRACUNIT
@@ -1216,7 +1216,8 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
((player && player != source->player) || (!player && target != source)) &&
target->IsTeammate (source))
{
- if (rawdamage < TELEFRAG_DAMAGE) //Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it.
+ //Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it.
+ if (rawdamage < TELEFRAG_DAMAGE || (target->flags7 & MF7_LAXTELEFRAGDMG))
{ // Still allow telefragging :-(
damage = (int)((float)damage * level.teamdamage);
if (damage < 0)
@@ -1250,8 +1251,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
}
// end of game hell hack
- if ((target->Sector->special & 255) == dDamage_End
- && damage >= target->health)
+ if ((target->Sector->Flags & SECF_ENDLEVEL) && damage >= target->health)
{
damage = target->health - 1;
}
diff --git a/src/p_lights.cpp b/src/p_lights.cpp
index 49ef130e8a..656b861124 100644
--- a/src/p_lights.cpp
+++ b/src/p_lights.cpp
@@ -786,12 +786,12 @@ int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev
l = new DPhased (sector, baselevel);
int numsteps = PhaseHelper (sector->NextSpecialSector (
- (sector->special & 0x00ff) == LightSequenceSpecial1 ?
+ sector->special == LightSequenceSpecial1 ?
LightSequenceSpecial2 : LightSequenceSpecial1, prev),
index + 1, l->m_BaseLevel, sector);
l->m_Phase = ((numsteps - index - 1) * 64) / numsteps;
- sector->special &= 0xff00;
+ sector->special = 0;
return numsteps;
}
@@ -820,7 +820,6 @@ DPhased::DPhased (sector_t *sector, int baselevel, int phase)
{
m_BaseLevel = baselevel;
m_Phase = phase;
- sector->special &= 0xff00;
}
//============================================================================
diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp
index 387f398b5c..d4783baf10 100644
--- a/src/p_lnspec.cpp
+++ b/src/p_lnspec.cpp
@@ -148,7 +148,7 @@ FUNC(LS_Polyobj_MoveToSpot)
FActorIterator iterator (arg2);
AActor *spot = iterator.Next();
if (spot == NULL) return false;
- return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->x, spot->y, false);
+ return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->X(), spot->Y(), false);
}
FUNC(LS_Polyobj_DoorSwing)
@@ -199,7 +199,7 @@ FUNC(LS_Polyobj_OR_MoveToSpot)
FActorIterator iterator (arg2);
AActor *spot = iterator.Next();
if (spot == NULL) return false;
- return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->x, spot->y, true);
+ return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->X(), spot->Y(), true);
}
FUNC(LS_Polyobj_Stop)
@@ -1945,6 +1945,9 @@ FUNC(LS_Sector_ChangeFlags)
rtn = false;
FSectorTagIterator itr(arg0);
+ // exclude protected flags
+ arg1 &= ~SECF_NOMODIFY;
+ arg2 &= ~SECF_NOMODIFY;
while ((secNum = itr.Next()) >= 0)
{
sectors[secNum].Flags = (sectors[secNum].Flags | arg1) & ~arg2;
@@ -2246,7 +2249,7 @@ FUNC(LS_PointPush_SetForce)
}
FUNC(LS_Sector_SetDamage)
-// Sector_SetDamage (tag, amount, mod)
+// Sector_SetDamage (tag, amount, mod, interval, leaky)
{
// The sector still stores the mod in its old format because
// adding an FName to the sector_t structure might cause
@@ -2257,8 +2260,28 @@ FUNC(LS_Sector_SetDamage)
int secnum;
while ((secnum = itr.Next()) >= 0)
{
- sectors[secnum].damage = arg1;
- sectors[secnum].mod = arg2;
+ if (arg3 <= 0) // emulate old and hacky method to handle leakiness.
+ {
+ if (arg1 < 20)
+ {
+ arg4 = 0;
+ arg3 = 32;
+ }
+ else if (arg1 < 50)
+ {
+ arg4 = 5;
+ arg3 = 32;
+ }
+ else
+ {
+ arg4 = 256;
+ arg3 = 1;
+ }
+ }
+ sectors[secnum].damageamount = (short)arg1;
+ sectors[secnum].damagetype = MODtoDamageType(arg2);
+ sectors[secnum].damageinterval = (short)arg3;
+ sectors[secnum].leakydamage = (short)arg4;
}
return true;
}
diff --git a/src/p_local.h b/src/p_local.h
index 14749a85da..b74bf2259e 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -253,6 +253,12 @@ inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line)
: DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0;
}
+inline int P_PointOnLineSidePrecise (fixed_t x, fixed_t y, const line_t *line)
+{
+ return DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0;
+}
+
+
//==========================================================================
//
// P_PointOnDivlineSide
@@ -271,6 +277,12 @@ inline int P_PointOnDivlineSide (fixed_t x, fixed_t y, const divline_t *line)
: (DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0);
}
+inline int P_PointOnDivlineSidePrecise (fixed_t x, fixed_t y, const divline_t *line)
+{
+ return DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0;
+}
+
+
//==========================================================================
//
// P_MakeDivline
@@ -297,6 +309,7 @@ struct FLineOpening
sector_t *topsec;
FTextureID ceilingpic;
FTextureID floorpic;
+ int floorterrain;
bool touchmidtex;
bool abovemidtex;
};
@@ -371,7 +384,6 @@ class FPathTraverse
divline_t trace;
unsigned int intercept_index;
unsigned int intercept_count;
- fixed_t maxfrac;
unsigned int count;
void AddLineIntercepts(int bx, int by);
@@ -412,6 +424,7 @@ struct FCheckPosition
fixed_t ceilingz;
fixed_t dropoffz;
FTextureID floorpic;
+ int floorterrain;
sector_t *floorsector;
FTextureID ceilingpic;
sector_t *ceilingsector;
@@ -455,7 +468,7 @@ bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane
bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor = NULL);
bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y);
void P_ApplyTorque(AActor *mo);
-bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag); // [RH] Added z and telefrag parameters
+bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag, bool modifyactor = true); // [RH] Added z and telefrag parameters
void P_PlayerStartStomp (AActor *actor); // [RH] Stomp on things for a newly spawned player
void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps);
bool P_BounceWall (AActor *mo);
@@ -512,7 +525,7 @@ void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch);
void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version
void P_TraceBleed (int damage, AActor *target); // random direction version
bool P_HitFloor (AActor *thing);
-bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true);
+bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true, bool force = false);
void P_CheckSplash(AActor *self, fixed_t distance);
void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, PClassActor *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, PClassActor *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun
diff --git a/src/p_map.cpp b/src/p_map.cpp
index 1addb464e5..bf1a4973b0 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -52,6 +52,7 @@
#include "p_conversation.h"
#include "r_data/r_translate.h"
#include "g_level.h"
+#include "r_sky.h"
CVAR(Bool, cl_bloodsplats, true, CVAR_ARCHIVE)
CVAR(Int, sv_smartaim, 0, CVAR_ARCHIVE | CVAR_SERVERINFO)
@@ -242,6 +243,7 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags)
tmf.floorz = tmf.dropoffz = sec->floorplane.ZatPoint(tmf.x, tmf.y);
tmf.ceilingz = sec->ceilingplane.ZatPoint(tmf.x, tmf.y);
tmf.floorpic = sec->GetTexture(sector_t::floor);
+ tmf.floorterrain = sec->GetTerrain(sector_t::floor);
tmf.ceilingpic = sec->GetTexture(sector_t::ceiling);
}
else
@@ -264,6 +266,7 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags)
{
tmf.dropoffz = tmf.floorz = ff_top;
tmf.floorpic = *rover->top.texture;
+ tmf.floorterrain = rover->model->GetTerrain(rover->top.isceiling);
}
}
if (ff_bottom <= tmf.ceilingz && ff_bottom > tmf.z + tmf.thing->height)
@@ -304,6 +307,7 @@ void P_FindFloorCeiling(AActor *actor, int flags)
tmf.floorz = tmf.dropoffz = actor->floorz;
tmf.ceilingz = actor->ceilingz;
tmf.floorpic = actor->floorpic;
+ tmf.floorterrain = actor->floorterrain;
tmf.ceilingpic = actor->ceilingpic;
P_GetFloorCeilingZ(tmf, flags);
}
@@ -311,6 +315,7 @@ void P_FindFloorCeiling(AActor *actor, int flags)
actor->dropoffz = tmf.dropoffz;
actor->ceilingz = tmf.ceilingz;
actor->floorpic = tmf.floorpic;
+ actor->floorterrain = tmf.floorterrain;
actor->floorsector = tmf.floorsector;
actor->ceilingpic = tmf.ceilingpic;
actor->ceilingsector = tmf.ceilingsector;
@@ -337,6 +342,7 @@ void P_FindFloorCeiling(AActor *actor, int flags)
actor->dropoffz = tmf.dropoffz;
actor->ceilingz = tmf.ceilingz;
actor->floorpic = tmf.floorpic;
+ actor->floorterrain = tmf.floorterrain;
actor->floorsector = tmf.floorsector;
actor->ceilingpic = tmf.ceilingpic;
actor->ceilingsector = tmf.ceilingsector;
@@ -348,6 +354,7 @@ void P_FindFloorCeiling(AActor *actor, int flags)
if (actor->Sector != NULL)
{
actor->floorpic = actor->Sector->GetTexture(sector_t::floor);
+ actor->floorterrain = actor->Sector->GetTerrain(sector_t::floor);
actor->ceilingpic = actor->Sector->GetTexture(sector_t::ceiling);
}
}
@@ -370,7 +377,7 @@ void P_FindFloorCeiling(AActor *actor, int flags)
//
//==========================================================================
-bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag)
+bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag, bool modifyactor)
{
FCheckPosition tmf;
sector_t *oldsec = thing->Sector;
@@ -449,36 +456,40 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra
return false;
}
- // the move is ok, so link the thing into its new position
- thing->SetOrigin(x, y, z);
- thing->floorz = tmf.floorz;
- thing->ceilingz = tmf.ceilingz;
- thing->floorsector = tmf.floorsector;
- thing->floorpic = tmf.floorpic;
- thing->ceilingsector = tmf.ceilingsector;
- thing->ceilingpic = tmf.ceilingpic;
- thing->dropoffz = tmf.dropoffz; // killough 11/98
- thing->BlockingLine = NULL;
-
- if (thing->flags2 & MF2_FLOORCLIP)
+ if (modifyactor)
{
- thing->AdjustFloorClip();
- }
+ // the move is ok, so link the thing into its new position
+ thing->SetOrigin(x, y, z);
+ thing->floorz = tmf.floorz;
+ thing->ceilingz = tmf.ceilingz;
+ thing->floorsector = tmf.floorsector;
+ thing->floorpic = tmf.floorpic;
+ thing->floorterrain = tmf.floorterrain;
+ thing->ceilingsector = tmf.ceilingsector;
+ thing->ceilingpic = tmf.ceilingpic;
+ thing->dropoffz = tmf.dropoffz; // killough 11/98
+ thing->BlockingLine = NULL;
- if (thing == players[consoleplayer].camera)
- {
- R_ResetViewInterpolation();
- }
+ if (thing->flags2 & MF2_FLOORCLIP)
+ {
+ thing->AdjustFloorClip();
+ }
- thing->PrevX = x;
- thing->PrevY = y;
- thing->PrevZ = z;
+ if (thing == players[consoleplayer].camera)
+ {
+ R_ResetViewInterpolation();
+ }
- // If this teleport was caused by a move, P_TryMove() will handle the
- // sector transition messages better than we can here.
- if (!(thing->flags6 & MF6_INTRYMOVE))
- {
- thing->CheckSectorTransition(oldsec);
+ thing->PrevX = x;
+ thing->PrevY = y;
+ thing->PrevZ = z;
+
+ // If this teleport was caused by a move, P_TryMove() will handle the
+ // sector transition messages better than we can here.
+ if (!(thing->flags6 & MF6_INTRYMOVE))
+ {
+ thing->CheckSectorTransition(oldsec);
+ }
}
return true;
@@ -529,16 +540,18 @@ void P_PlayerStartStomp(AActor *actor)
//
//==========================================================================
-inline fixed_t secfriction(const sector_t *sec)
+inline fixed_t secfriction(const sector_t *sec, int plane = sector_t::floor)
{
- fixed_t friction = Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction;
- return friction != 0 ? friction : sec->friction;
+ if (sec->Flags & SECF_FRICTION) return sec->friction;
+ fixed_t friction = Terrains[sec->GetTerrain(plane)].Friction;
+ return friction != 0 ? friction : ORIG_FRICTION;
}
-inline fixed_t secmovefac(const sector_t *sec)
+inline fixed_t secmovefac(const sector_t *sec, int plane = sector_t::floor)
{
- fixed_t movefactor = Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].MoveFactor;
- return movefactor != 0 ? movefactor : sec->movefactor;
+ if (sec->Flags & SECF_FRICTION) return sec->movefactor;
+ fixed_t movefactor = Terrains[sec->GetTerrain(plane)].MoveFactor;
+ return movefactor != 0 ? movefactor : ORIG_FRICTION_FACTOR;
}
//==========================================================================
@@ -580,15 +593,15 @@ int P_GetFriction(const AActor *mo, int *frictionfactor)
if (!(rover->flags & FF_EXISTS)) continue;
if (!(rover->flags & FF_SWIMMABLE)) continue;
- if (mo->z > rover->top.plane->ZatPoint(mo->x, mo->y) ||
- mo->z < rover->bottom.plane->ZatPoint(mo->x, mo->y))
+ if (mo->z > rover->top.plane->ZatPoint(mo) ||
+ mo->z < rover->bottom.plane->ZatPoint(mo))
continue;
- newfriction = secfriction(rover->model);
+ newfriction = secfriction(rover->model, rover->top.isceiling);
if (newfriction < friction || friction == ORIG_FRICTION)
{
friction = newfriction;
- movefactor = secmovefac(rover->model) >> 1;
+ movefactor = secmovefac(rover->model, rover->top.isceiling) >> 1;
}
}
}
@@ -610,36 +623,36 @@ int P_GetFriction(const AActor *mo, int *frictionfactor)
if (rover->flags & FF_SOLID)
{
// Must be standing on a solid floor
- if (mo->z != rover->top.plane->ZatPoint(mo->x, mo->y)) continue;
+ if (mo->z != rover->top.plane->ZatPoint(mo)) continue;
}
else if (rover->flags & FF_SWIMMABLE)
{
// Or on or inside a swimmable floor (e.g. in shallow water)
- if (mo->z > rover->top.plane->ZatPoint(mo->x, mo->y) ||
- (mo->z + mo->height) < rover->bottom.plane->ZatPoint(mo->x, mo->y))
+ if (mo->z > rover->top.plane->ZatPoint(mo) ||
+ (mo->z + mo->height) < rover->bottom.plane->ZatPoint(mo))
continue;
}
else
continue;
- newfriction = secfriction(rover->model);
+ newfriction = secfriction(rover->model, rover->top.isceiling);
if (newfriction < friction || friction == ORIG_FRICTION)
{
friction = newfriction;
- movefactor = secmovefac(rover->model);
+ movefactor = secmovefac(rover->model, rover->top.isceiling);
}
}
- if (!(sec->special & FRICTION_MASK) &&
- Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction == 0)
+ if (!(sec->Flags & SECF_FRICTION) &&
+ Terrains[sec->GetTerrain(sector_t::floor)].Friction == 0)
{
continue;
}
newfriction = secfriction(sec);
if ((newfriction < friction || friction == ORIG_FRICTION) &&
- (mo->z <= sec->floorplane.ZatPoint(mo->x, mo->y) ||
+ (mo->z <= sec->floorplane.ZatPoint(mo) ||
(sec->GetHeightSec() != NULL &&
- mo->z <= sec->heightsec->floorplane.ZatPoint(mo->x, mo->y))))
+ mo->z <= sec->heightsec->floorplane.ZatPoint(mo))))
{
friction = newfriction;
movefactor = secmovefac(sec);
@@ -889,6 +902,7 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
tm.floorz = open.bottom;
tm.floorsector = open.bottomsec;
tm.floorpic = open.floorpic;
+ tm.floorterrain = open.floorterrain;
tm.touchmidtex = open.touchmidtex;
tm.abovemidtex = open.abovemidtex;
tm.thing->BlockingLine = ld;
@@ -1065,8 +1079,8 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
abs(thing->y - tm.thing->y) < (thing->radius+tm.thing->radius))
{
- fixed_t newdist = P_AproxDistance(thing->x - tm.x, thing->y - tm.y);
- fixed_t olddist = P_AproxDistance(thing->x - tm.thing->x, thing->y - tm.thing->y);
+ fixed_t newdist = thing->AproxDistance(tm.x, tm.y, tm.thing);
+ fixed_t olddist = thing->AproxDistance(tm.thing);
if (newdist > olddist)
{
@@ -1434,6 +1448,7 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo
tm.floorz = tm.dropoffz = newsec->floorplane.ZatPoint(x, y);
tm.ceilingz = newsec->ceilingplane.ZatPoint(x, y);
tm.floorpic = newsec->GetTexture(sector_t::floor);
+ tm.floorterrain = newsec->GetTerrain(sector_t::floor);
tm.floorsector = newsec;
tm.ceilingpic = newsec->GetTexture(sector_t::ceiling);
tm.ceilingsector = newsec;
@@ -1466,6 +1481,7 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo
{
tm.floorz = tm.dropoffz = ff_top;
tm.floorpic = *rover->top.texture;
+ tm.floorterrain = rover->model->GetTerrain(rover->top.isceiling);
}
if (ff_bottom < tm.ceilingz && abs(delta1) >= abs(delta2))
{
@@ -1742,7 +1758,7 @@ void P_FakeZMovement(AActor *mo)
{ // float down towards target if too close
if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT))
{
- fixed_t dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y);
+ fixed_t dist = mo->AproxDistance(mo->target);
fixed_t delta = (mo->target->z + (mo->height >> 1)) - mo->z;
if (delta < 0 && dist < -(delta * 3))
mo->z -= mo->FloatSpeed;
@@ -1782,10 +1798,10 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo
if (windowcheck && !(ib_compatflags & BCOMPATF_NOWINDOWCHECK) && line->backsector != NULL)
{ // Make sure this line actually blocks us and is not a window
// or similar construct we are standing inside of.
- fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(mobj->x, mobj->y);
- fixed_t fzb = line->frontsector->floorplane.ZatPoint(mobj->x, mobj->y);
- fixed_t bzt = line->backsector->ceilingplane.ZatPoint(mobj->x, mobj->y);
- fixed_t bzb = line->backsector->floorplane.ZatPoint(mobj->x, mobj->y);
+ fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(mobj);
+ fixed_t fzb = line->frontsector->floorplane.ZatPoint(mobj);
+ fixed_t bzt = line->backsector->ceilingplane.ZatPoint(mobj);
+ fixed_t bzb = line->backsector->floorplane.ZatPoint(mobj);
if (fzt >= mobj->z + mobj->height && bzt >= mobj->z + mobj->height &&
fzb <= mobj->z && bzb <= mobj->z)
{
@@ -1796,8 +1812,8 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo
if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
- fixed_t ff_bottom = rover->bottom.plane->ZatPoint(mobj->x, mobj->y);
- fixed_t ff_top = rover->top.plane->ZatPoint(mobj->x, mobj->y);
+ fixed_t ff_bottom = rover->bottom.plane->ZatPoint(mobj);
+ fixed_t ff_top = rover->top.plane->ZatPoint(mobj);
if (ff_bottom < mobj->z + mobj->height && ff_top > mobj->z)
{
@@ -2067,8 +2083,8 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
{
fixed_t eyez = oldz + viewheight;
- oldAboveFakeFloor = eyez > oldsec->heightsec->floorplane.ZatPoint(thing->x, thing->y);
- oldAboveFakeCeiling = eyez > oldsec->heightsec->ceilingplane.ZatPoint(thing->x, thing->y);
+ oldAboveFakeFloor = eyez > oldsec->heightsec->floorplane.ZatPoint(thing);
+ oldAboveFakeCeiling = eyez > oldsec->heightsec->ceilingplane.ZatPoint(thing);
}
// Borrowed from MBF:
@@ -2089,6 +2105,7 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
thing->ceilingz = tm.ceilingz;
thing->dropoffz = tm.dropoffz; // killough 11/98: keep track of dropoffs
thing->floorpic = tm.floorpic;
+ thing->floorterrain = tm.floorterrain;
thing->floorsector = tm.floorsector;
thing->ceilingpic = tm.ceilingpic;
thing->ceilingsector = tm.ceilingsector;
@@ -2726,14 +2743,14 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov
}
const secplane_t *plane = &actor->floorsector->floorplane;
- fixed_t planezhere = plane->ZatPoint(actor->x, actor->y);
+ fixed_t planezhere = plane->ZatPoint(actor);
for (unsigned int i = 0; ifloorsector->e->XFloor.ffloors.Size(); i++)
{
F3DFloor * rover = actor->floorsector->e->XFloor.ffloors[i];
if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
- fixed_t thisplanez = rover->top.plane->ZatPoint(actor->x, actor->y);
+ fixed_t thisplanez = rover->top.plane->ZatPoint(actor);
if (thisplanez>planezhere && thisplanez <= actor->z + actor->MaxStepHeight)
{
@@ -2751,7 +2768,7 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov
F3DFloor * rover = actor->Sector->e->XFloor.ffloors[i];
if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
- fixed_t thisplanez = rover->top.plane->ZatPoint(actor->x, actor->y);
+ fixed_t thisplanez = rover->top.plane->ZatPoint(actor);
if (thisplanez>planezhere && thisplanez <= actor->z + actor->MaxStepHeight)
{
@@ -3053,7 +3070,7 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop)
if (!ontop)
{
fixed_t speed;
- angle_t angle = R_PointToAngle2(BlockingMobj->x,BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce() % 16) - 8);
+ angle_t angle = BlockingMobj->AngleTo(mo) + ANGLE_1*((pr_bounce() % 16) - 8);
speed = P_AproxDistance(mo->velx, mo->vely);
speed = FixedMul(speed, mo->wallbouncefactor); // [GZ] was 0.75, using wallbouncefactor seems more consistent
mo->angle = angle;
@@ -4071,7 +4088,7 @@ void P_TraceBleed(int damage, AActor *target, AActor *missile)
pitch = 0;
}
P_TraceBleed(damage, target->x, target->y, target->z + target->height / 2,
- target, R_PointToAngle2(missile->x, missile->y, target->x, target->y),
+ target, missile->AngleTo(target),
pitch);
}
@@ -4280,6 +4297,8 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF)
{
puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0);
+ if (puff && (trace.Line != NULL) && (trace.Line->special == Line_Horizon) && !(puff->flags3 & MF3_SKYEXPLODE))
+ puff->Destroy();
}
if (puff != NULL && puffDefaults->flags7 & MF7_FORCEDECAL && puff->DecalGenerator)
SpawnShootDecal(puff, trace);
@@ -4287,6 +4306,20 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
SpawnShootDecal(source, trace);
}
+ if (trace.HitType == TRACE_HitFloor || trace.HitType == TRACE_HitCeiling)
+ {
+ AActor* puff = NULL;
+ if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF)
+ {
+ puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0);
+ if (puff && !(puff->flags3 & MF3_SKYEXPLODE) &&
+ (((trace.HitType == TRACE_HitFloor) && (puff->floorpic == skyflatnum)) ||
+ ((trace.HitType == TRACE_HitCeiling) && (puff->ceilingpic == skyflatnum))))
+ {
+ puff->Destroy();
+ }
+ }
+ }
if (thepuff != NULL)
{
if (trace.HitType == TRACE_HitFloor &&
@@ -4843,7 +4876,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo
{
velz *= 0.8f;
}
- angle_t ang = R_PointToAngle2(bombspot->x, bombspot->y, thing->x, thing->y) >> ANGLETOFINESHIFT;
+ angle_t ang = bombspot->AngleTo(thing) >> ANGLETOFINESHIFT;
thing->velx += fixed_t(finecosine[ang] * thrust);
thing->vely += fixed_t(finesine[ang] * thrust);
if (!(flags & RADF_NODAMAGE))
@@ -4952,6 +4985,7 @@ bool P_AdjustFloorCeil(AActor *thing, FChangePosition *cpos)
thing->ceilingz = tm.ceilingz;
thing->dropoffz = tm.dropoffz; // killough 11/98: remember dropoffs
thing->floorpic = tm.floorpic;
+ thing->floorterrain = tm.floorterrain;
thing->floorsector = tm.floorsector;
thing->ceilingpic = tm.ceilingpic;
thing->ceilingsector = tm.ceilingsector;
diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp
index 0a39460e7d..1c7a205a19 100644
--- a/src/p_maputl.cpp
+++ b/src/p_maputl.cpp
@@ -194,6 +194,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
open.bottom = ff;
open.bottomsec = front;
open.floorpic = front->GetTexture(sector_t::floor);
+ open.floorterrain = front->GetTerrain(sector_t::floor);
open.lowfloor = bf;
}
else
@@ -201,6 +202,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
open.bottom = bf;
open.bottomsec = back;
open.floorpic = back->GetTexture(sector_t::floor);
+ open.floorterrain = back->GetTerrain(sector_t::floor);
open.lowfloor = ff;
}
}
@@ -211,6 +213,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
open.top = FIXED_MAX;
open.bottomsec = NULL;
open.floorpic.SetInvalid();
+ open.floorterrain = -1;
open.bottom = FIXED_MIN;
open.lowfloor = FIXED_MAX;
}
@@ -582,7 +585,7 @@ sector_t *AActor::LinkToWorldForMapThing ()
return ssec->sector;
}
-void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz)
+void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz, bool moving)
{
UnlinkFromWorld ();
x = ix;
@@ -982,7 +985,7 @@ void FPathTraverse::AddLineIntercepts(int bx, int by)
P_MakeDivline (ld, &dl);
frac = P_InterceptVector (&trace, &dl);
- if (frac < 0) continue; // behind source
+ if (frac < 0 || frac > FRACUNIT) continue; // behind source or beyond end point
intercept_t newintercept;
@@ -1053,13 +1056,13 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it
break;
}
// Check if this side is facing the trace origin
- if (P_PointOnDivlineSide (trace.x, trace.y, &line) == 0)
+ if (P_PointOnDivlineSidePrecise (trace.x, trace.y, &line) == 0)
{
numfronts++;
// If it is, see if the trace crosses it
- if (P_PointOnDivlineSide (line.x, line.y, &trace) !=
- P_PointOnDivlineSide (line.x + line.dx, line.y + line.dy, &trace))
+ if (P_PointOnDivlineSidePrecise (line.x, line.y, &trace) !=
+ P_PointOnDivlineSidePrecise (line.x + line.dx, line.y + line.dy, &trace))
{
// It's a hit
fixed_t frac = P_InterceptVector (&trace, &line);
@@ -1167,7 +1170,7 @@ intercept_t *FPathTraverse::Next()
}
}
- if (dist > maxfrac || in == NULL) return NULL; // checked everything in range
+ if (dist > FRACUNIT || in == NULL) return NULL; // checked everything in range
in->done = true;
return in;
}
@@ -1385,7 +1388,6 @@ FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, in
break;
}
}
- maxfrac = FRACUNIT;
}
FPathTraverse::~FPathTraverse()
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 9e04e2a24e..59770d13a7 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -276,6 +276,10 @@ void AActor::Serialize (FArchive &arc)
arc << dmg;
Damage = UncalcDamageValue(dmg, GetDefault()->Damage);
}
+ if (SaveVersion >= 4530)
+ {
+ P_SerializeTerrain(arc, floorterrain);
+ }
if (SaveVersion >= 3227)
{
arc << projectileKickback;
@@ -1375,7 +1379,7 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target)
if (line != NULL && cl_missiledecals)
{
- int side = P_PointOnLineSide (mo->x, mo->y, line);
+ int side = P_PointOnLineSidePrecise (mo->x, mo->y, line);
if (line->sidedef[side] == NULL)
side ^= 1;
if (line->sidedef[side] != NULL)
@@ -1647,7 +1651,7 @@ int P_FaceMobj (AActor *source, AActor *target, angle_t *delta)
angle_t angle2;
angle1 = source->angle;
- angle2 = R_PointToAngle2 (source->x, source->y, target->x, target->y);
+ angle2 = source->AngleTo(target);
if (angle2 > angle1)
{
diff = angle2 - angle1;
@@ -1760,8 +1764,7 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool preci
if (actor->z + actor->height < target->z ||
target->z + target->height < actor->z)
{ // Need to seek vertically
- dist = P_AproxDistance (target->x - actor->x, target->y - actor->y);
- dist = dist / speed;
+ dist = actor->AproxDistance (target) / speed;
if (dist < 1)
{
dist = 1;
@@ -2111,7 +2114,7 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
// Don't change the angle if there's THRUREFLECT on the monster.
if (!(BlockingMobj->flags7 & MF7_THRUREFLECT))
{
- angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y);
+ angle = BlockingMobj->AngleTo(mo);
bool dontReflect = (mo->AdjustReflectionAngle(BlockingMobj, angle));
// Change angle for deflection/reflection
@@ -2169,7 +2172,7 @@ explode:
if (tm.ceilingline &&
tm.ceilingline->backsector &&
tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum &&
- mo->z >= tm.ceilingline->backsector->ceilingplane.ZatPoint (mo->x, mo->y))
+ mo->z >= tm.ceilingline->backsector->ceilingplane.ZatPoint(mo))
{
// Hack to prevent missiles exploding against the sky.
// Does not handle sky floors.
@@ -2253,7 +2256,7 @@ explode:
{ // Don't stop sliding if halfway off a step with some velocity
if (mo->velx > FRACUNIT/4 || mo->velx < -FRACUNIT/4 || mo->vely > FRACUNIT/4 || mo->vely < -FRACUNIT/4)
{
- if (mo->floorz > mo->Sector->floorplane.ZatPoint (mo->x, mo->y))
+ if (mo->floorz > mo->Sector->floorplane.ZatPoint(mo))
{
if (mo->dropoffz != mo->floorz) // 3DMidtex or other special cases that must be excluded
{
@@ -2471,7 +2474,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
{ // float down towards target if too close
if (!(mo->flags & (MF_SKULLFLY | MF_INFLOAT)))
{
- dist = P_AproxDistance (mo->x - mo->target->x, mo->y - mo->target->y);
+ dist = mo->AproxDistance (mo->target);
delta = (mo->target->z + (mo->height>>1)) - mo->z;
if (delta < 0 && dist < -(delta*3))
mo->z -= mo->FloatSpeed;
@@ -2499,7 +2502,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
{ // Hit the floor
if ((!mo->player || !(mo->player->cheats & CF_PREDICTING)) &&
mo->Sector->SecActTarget != NULL &&
- mo->Sector->floorplane.ZatPoint (mo->x, mo->y) == mo->floorz)
+ mo->Sector->floorplane.ZatPoint(mo) == mo->floorz)
{ // [RH] Let the sector do something to the actor
mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor);
}
@@ -2601,7 +2604,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
{ // hit the ceiling
if ((!mo->player || !(mo->player->cheats & CF_PREDICTING)) &&
mo->Sector->SecActTarget != NULL &&
- mo->Sector->ceilingplane.ZatPoint (mo->x, mo->y) == mo->ceilingz)
+ mo->Sector->ceilingplane.ZatPoint(mo) == mo->ceilingz)
{ // [RH] Let the sector do something to the actor
mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling);
}
@@ -2656,7 +2659,7 @@ void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheigh
if (sec->heightsec != NULL && sec->SecActTarget != NULL)
{
sector_t *hs = sec->heightsec;
- fixed_t waterz = hs->floorplane.ZatPoint (mo->x, mo->y);
+ fixed_t waterz = hs->floorplane.ZatPoint(mo);
fixed_t newz;
fixed_t viewheight;
@@ -2691,7 +2694,7 @@ void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheigh
if (!(hs->MoreFlags & SECF_FAKEFLOORONLY))
{
- waterz = hs->ceilingplane.ZatPoint (mo->x, mo->y);
+ waterz = hs->ceilingplane.ZatPoint(mo);
if (oldz <= waterz && newz > waterz)
{ // View went above fake ceiling
sec->SecActTarget->TriggerAction (mo, SECSPAC_EyesAboveC);
@@ -3193,8 +3196,7 @@ bool AActor::IsOkayToAttack (AActor *link)
// to only allow the check to succeed if the enemy was in a ~84� FOV of the player
if (flags3 & MF3_SCREENSEEKER)
{
- angle_t angle = R_PointToAngle2(Friend->x,
- Friend->y, link->x, link->y) - Friend->angle;
+ angle_t angle = Friend->AngleTo(link) - Friend->angle;
angle >>= 24;
if (angle>226 || angle<30)
{
@@ -3496,7 +3498,7 @@ void AActor::Tick ()
if (health > 0
&& !players[i].Bot->enemy
&& player ? !IsTeammate (players[i].mo) : true
- && P_AproxDistance (players[i].mo->x-x, players[i].mo->y-y) < MAX_MONSTER_TARGET_DIST
+ && AproxDistance (players[i].mo) < MAX_MONSTER_TARGET_DIST
&& P_CheckSight (players[i].mo, this, SF_SEEPASTBLOCKEVERYTHING))
{ //Probably a monster, so go kill it.
players[i].Bot->enemy = this;
@@ -3560,7 +3562,7 @@ void AActor::Tick ()
if (player != NULL)
{
- int scrolltype = sec->special & 0xff;
+ int scrolltype = sec->special;
if (scrolltype >= Scroll_North_Slow &&
scrolltype <= Scroll_SouthWest_Fast)
@@ -4139,6 +4141,7 @@ AActor *AActor::StaticSpawn (PClassActor *type, fixed_t ix, fixed_t iy, fixed_t
{
actor->floorsector = actor->Sector;
actor->floorpic = actor->floorsector->GetTexture(sector_t::floor);
+ actor->floorterrain = actor->floorsector->GetTerrain(sector_t::floor);
actor->ceilingsector = actor->Sector;
actor->ceilingpic = actor->ceilingsector->GetTexture(sector_t::ceiling);
}
@@ -4150,6 +4153,7 @@ AActor *AActor::StaticSpawn (PClassActor *type, fixed_t ix, fixed_t iy, fixed_t
else
{
actor->floorpic = actor->Sector->GetTexture(sector_t::floor);
+ actor->floorterrain = actor->Sector->GetTerrain(sector_t::floor);
actor->floorsector = actor->Sector;
actor->ceilingpic = actor->Sector->GetTexture(sector_t::ceiling);
actor->ceilingsector = actor->Sector;
@@ -4447,7 +4451,7 @@ void AActor::AdjustFloorClip ()
sector_t *hsec = m->m_sector->GetHeightSec();
if (hsec == NULL && m->m_sector->floorplane.ZatPoint (x, y) == z)
{
- fixed_t clip = Terrains[TerrainTypes[m->m_sector->GetTexture(sector_t::floor)]].FootClip;
+ fixed_t clip = Terrains[m->m_sector->GetTerrain(sector_t::floor)].FootClip;
if (clip < shallowestclip)
{
shallowestclip = clip;
@@ -4532,7 +4536,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
( gameaction != ga_worlddone ) &&
( p->mo != NULL ) &&
( !(p->mo->Sector->Flags & SECF_NORESPAWN) ) &&
- ( (p->mo->Sector->special & 255) != Damage_InstantDeath ))
+ ( p->mo->Sector->damageamount < TELEFRAG_DAMAGE )) // this really should be a bit smarter...
{
spawn_x = p->mo->x;
spawn_y = p->mo->y;
@@ -4782,10 +4786,10 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
}
// copy args to mapthing so that we have them in one place for the rest of this function
- if (mentry->ArgsDefined)
+ if (mentry->ArgsDefined > 0)
{
if (mentry->Type!= NULL) mthing->special = mentry->Special;
- memcpy(mthing->args, mentry->Args, sizeof(mthing->args));
+ memcpy(mthing->args, mentry->Args, sizeof(mthing->args[0]) * mentry->ArgsDefined);
}
int pnum = -1;
@@ -5139,7 +5143,7 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y
puff->target = source;
- if (source != NULL) puff->angle = R_PointToAngle2(x, y, source->x, source->y);
+ if (source != NULL) puff->angle = puff->AngleTo(source);
// If a puff has a crash state and an actor was not hit,
// it will enter the crash state. This is used by the StrifeSpark
@@ -5413,13 +5417,13 @@ void P_RipperBlood (AActor *mo, AActor *bleeder)
int P_GetThingFloorType (AActor *thing)
{
- if (thing->floorpic.isValid())
+ if (thing->floorterrain >= 0)
{
- return TerrainTypes[thing->floorpic];
+ return thing->floorterrain;
}
else
{
- return TerrainTypes[thing->Sector->GetTexture(sector_t::floor)];
+ return thing->Sector->GetTerrain(sector_t::floor);
}
}
@@ -5430,7 +5434,7 @@ int P_GetThingFloorType (AActor *thing)
// Returns true if hit liquid and splashed, false if not.
//---------------------------------------------------------------------------
-bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool checkabove, bool alert)
+bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool checkabove, bool alert, bool force)
{
if (thing->flags3 & MF3_DONTSPLASH)
return false;
@@ -5472,30 +5476,34 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z
}
#endif
- for(unsigned int i=0;ie->XFloor.ffloors.Size();i++)
- {
+ // 'force' means, we want this sector's terrain, no matter what.
+ if (!force)
+ {
+ for (unsigned int i = 0; ie->XFloor.ffloors.Size(); i++)
+ {
F3DFloor * rover = sec->e->XFloor.ffloors[i];
if (!(rover->flags & FF_EXISTS)) continue;
fixed_t planez = rover->top.plane->ZatPoint(x, y);
- if (z > planez - FRACUNIT/2 && z < planez + FRACUNIT/2) // allow minor imprecisions
+ if (z > planez - FRACUNIT / 2 && z < planez + FRACUNIT / 2) // allow minor imprecisions
{
- if (rover->flags & (FF_SOLID|FF_SWIMMABLE) )
+ if (rover->flags & (FF_SOLID | FF_SWIMMABLE))
{
- terrainnum = TerrainTypes[*rover->top.texture];
+ terrainnum = rover->model->GetTerrain(rover->top.isceiling);
goto foundone;
}
}
planez = rover->bottom.plane->ZatPoint(x, y);
if (planez < z && !(planez < thing->floorz)) return false;
}
+ }
hsec = sec->GetHeightSec();
- if (hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES))
+ if (force || hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES))
{
- terrainnum = TerrainTypes[sec->GetTexture(sector_t::floor)];
+ terrainnum = sec->GetTerrain(sector_t::floor);
}
else
{
- terrainnum = TerrainTypes[hsec->GetTexture(sector_t::floor)];
+ terrainnum = hsec->GetTerrain(sector_t::floor);
}
foundone:
@@ -5513,7 +5521,7 @@ foundone:
// Don't splash for living things with small vertical velocities.
// There are levels where the constant splashing from the monsters gets extremely annoying
- if ((thing->flags3&MF3_ISMONSTER || thing->player) && thing->velz >= -6*FRACUNIT)
+ if (((thing->flags3&MF3_ISMONSTER || thing->player) && thing->velz >= -6*FRACUNIT) && !force)
return Terrains[terrainnum].IsLiquid;
splash = &Splashes[splashnum];
@@ -5595,7 +5603,7 @@ bool P_HitFloor (AActor *thing)
// don't splash if landing on the edge above water/lava/etc....
for (m = thing->touching_sectorlist; m; m = m->m_tnext)
{
- if (thing->z == m->m_sector->floorplane.ZatPoint (thing->x, thing->y))
+ if (thing->z == m->m_sector->floorplane.ZatPoint(thing))
{
break;
}
@@ -5607,7 +5615,7 @@ bool P_HitFloor (AActor *thing)
if (!(rover->flags & FF_EXISTS)) continue;
if (rover->flags & (FF_SOLID|FF_SWIMMABLE))
{
- if (rover->top.plane->ZatPoint(thing->x, thing->y) == thing->z)
+ if (rover->top.plane->ZatPoint(thing) == thing->z)
{
return P_HitWater (thing, m->m_sector);
}
@@ -5884,12 +5892,12 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct
P_PlaySpawnSound(th, source);
th->target = owner; // record missile's originator
- th->angle = an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y);
+ th->angle = an = source->AngleTo(dest);
an >>= ANGLETOFINESHIFT;
th->velx = FixedMul (th->Speed, finecosine[an]);
th->vely = FixedMul (th->Speed, finesine[an]);
- dist = P_AproxDistance (dest->x - source->x, dest->y - source->y);
+ dist = source->AproxDistance (dest);
if (th->Speed) dist = dist / th->Speed;
if (dist < 1)
@@ -5950,7 +5958,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, PClassAct
{
an += pr_spawnmissile.Random2() << 20;
}
- dist = P_AproxDistance (dest->x - source->x, dest->y - source->y);
+ dist = source->AproxDistance (dest);
speed = GetDefaultSpeed (type);
dist /= speed;
velz = dist != 0 ? (dest->z - source->z)/dist : speed;
diff --git a/src/p_pillar.cpp b/src/p_pillar.cpp
index 884218bee7..b1cae3af9b 100644
--- a/src/p_pillar.cpp
+++ b/src/p_pillar.cpp
@@ -198,17 +198,20 @@ DPillar::DPillar (sector_t *sector, EPillar type, fixed_t speed,
m_FloorSpeed = Scale (speed, floordist, ceilingdist);
}
- if (sector->seqType >= 0)
+ if (!(m_Sector->Flags & SECF_SILENTMOVE))
{
- SN_StartSequence (sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0);
- }
- else if (sector->SeqName != NAME_None)
- {
- SN_StartSequence (sector, CHAN_FLOOR, sector->SeqName, 0);
- }
- else
- {
- SN_StartSequence (sector, CHAN_FLOOR, "Floor", 0);
+ if (sector->seqType >= 0)
+ {
+ SN_StartSequence(sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0);
+ }
+ else if (sector->SeqName != NAME_None)
+ {
+ SN_StartSequence(sector, CHAN_FLOOR, sector->SeqName, 0);
+ }
+ else
+ {
+ SN_StartSequence(sector, CHAN_FLOOR, "Floor", 0);
+ }
}
}
diff --git a/src/p_plats.cpp b/src/p_plats.cpp
index 7600637b2f..b0697fc34b 100644
--- a/src/p_plats.cpp
+++ b/src/p_plats.cpp
@@ -72,6 +72,8 @@ void DPlat::Serialize (FArchive &arc)
void DPlat::PlayPlatSound (const char *sound)
{
+ if (m_Sector->Flags & SECF_SILENTMOVE) return;
+
if (m_Sector->seqType >= 0)
{
SN_StartSequence (m_Sector, CHAN_FLOOR, m_Sector->seqType, SEQ_PLATFORM, 0);
@@ -280,8 +282,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height,
{
if (line)
sec->SetTexture(sector_t::floor, line->sidedef[0]->sector->GetTexture(sector_t::floor));
- if (change == 1)
- sec->special &= SECRET_MASK; // Stop damage and other stuff, if any
+ if (change == 1) sec->ClearSpecial();
}
switch (type)
@@ -293,7 +294,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height,
plat->m_Low = sec->floorplane.d;
plat->m_Status = DPlat::up;
plat->PlayPlatSound ("Floor");
- sec->special &= SECRET_MASK; // NO MORE DAMAGE, IF APPLICABLE
+ sec->ClearSpecial();
break;
case DPlat::platUpByValue:
diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp
index 4804943203..7623104d7d 100644
--- a/src/p_saveg.cpp
+++ b/src/p_saveg.cpp
@@ -52,6 +52,7 @@
#include "farchive.h"
#include "p_lnspec.h"
#include "p_acs.h"
+#include "p_terrain.h"
static void CopyPlayer (player_t *dst, player_t *src, const char *name);
static void ReadOnePlayer (FArchive &arc, bool skipload);
@@ -354,7 +355,7 @@ void P_SerializeWorld (FArchive &arc)
short tag;
arc << tag;
}
- arc << sec->soundtraversed
+ arc << sec->soundtraversed
<< sec->seqType
<< sec->friction
<< sec->movefactor
@@ -368,18 +369,66 @@ void P_SerializeWorld (FArchive &arc)
<< sec->planes[sector_t::ceiling]
<< sec->heightsec
<< sec->bottommap << sec->midmap << sec->topmap
- << sec->gravity
- << sec->damage
- << sec->mod
- << sec->SoundTarget
+ << sec->gravity;
+ if (SaveVersion >= 4530)
+ {
+ P_SerializeTerrain(arc, sec->terrainnum[0]);
+ P_SerializeTerrain(arc, sec->terrainnum[1]);
+ }
+ if (SaveVersion >= 4529)
+ {
+ arc << sec->damageamount;
+ }
+ else
+ {
+ short dmg;
+ arc << dmg;
+ sec->damageamount = dmg;
+ }
+ if (SaveVersion >= 4528)
+ {
+ arc << sec->damageinterval
+ << sec->leakydamage
+ << sec->damagetype;
+ }
+ else
+ {
+ short damagemod;
+ arc << damagemod;
+ sec->damagetype = MODtoDamageType(damagemod);
+ if (sec->damageamount < 20)
+ {
+ sec->leakydamage = 0;
+ sec->damageinterval = 32;
+ }
+ else if (sec->damageamount < 50)
+ {
+ sec->leakydamage = 5;
+ sec->damageinterval = 32;
+ }
+ else
+ {
+ sec->leakydamage = 256;
+ sec->damageinterval = 1;
+ }
+ }
+
+ arc << sec->SoundTarget
<< sec->SecActTarget
<< sec->sky
<< sec->MoreFlags
<< sec->Flags
- << sec->FloorSkyBox << sec->CeilingSkyBox
- << sec->ZoneNumber
- << sec->secretsector
- << sec->interpolations[0]
+ << sec->SkyBoxes[sector_t::floor] << sec->SkyBoxes[sector_t::ceiling]
+ << sec->ZoneNumber;
+ if (SaveVersion < 4529)
+ {
+ short secretsector;
+ arc << secretsector;
+ if (secretsector) sec->Flags |= SECF_WASSECRET;
+ sec->special &= ~(SECRET_MASK|FRICTION_MASK|PUSH_MASK);
+ P_InitSectorSpecial(sec, sec->special, true);
+ }
+ arc << sec->interpolations[0]
<< sec->interpolations[1]
<< sec->interpolations[2]
<< sec->interpolations[3]
diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp
index 361b220a7d..83adc438f0 100644
--- a/src/p_sectors.cpp
+++ b/src/p_sectors.cpp
@@ -26,6 +26,7 @@
#include "doomstat.h"
#include "g_level.h"
#include "nodebuild.h"
+#include "p_terrain.h"
#include "po_man.h"
#include "farchive.h"
#include "r_utility.h"
@@ -49,7 +50,7 @@ sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const
if (NULL != (tsec = getNextSector (ln, this)) &&
tsec != nogood &&
- (tsec->special & 0x00ff) == type)
+ tsec->special == type)
{
return tsec;
}
@@ -804,16 +805,8 @@ int sector_t::GetCeilingLight () const
ASkyViewpoint *sector_t::GetSkyBox(int which)
{
- if (which == floor)
- {
- if (FloorSkyBox != NULL) return FloorSkyBox;
- if (MoreFlags & SECF_NOFLOORSKYBOX) return NULL;
- }
- else
- {
- if (CeilingSkyBox != NULL) return CeilingSkyBox;
- if (MoreFlags & SECF_NOCEILINGSKYBOX) return NULL;
- }
+ if (SkyBoxes[which] != NULL) return SkyBoxes[which];
+ if (MoreFlags & (SECF_NOFLOORSKYBOX << which)) return NULL;
return level.DefaultSkybox;
}
@@ -843,6 +836,65 @@ sector_t *sector_t::GetHeightSec() const
}
+void sector_t::GetSpecial(secspecial_t *spec)
+{
+ spec->special = special;
+ spec->damageamount = damageamount;
+ spec->damagetype = damagetype;
+ spec->damageinterval = damageinterval;
+ spec->leakydamage = leakydamage;
+ spec->Flags = Flags & SECF_SPECIALFLAGS;
+}
+
+void sector_t::SetSpecial(const secspecial_t *spec)
+{
+ special = spec->special;
+ damageamount = spec->damageamount;
+ damagetype = spec->damagetype;
+ damageinterval = spec->damageinterval;
+ leakydamage = spec->leakydamage;
+ Flags = (Flags & ~SECF_SPECIALFLAGS) | (spec->Flags & SECF_SPECIALFLAGS);
+}
+
+void sector_t::TransferSpecial(sector_t *model)
+{
+ special = model->special;
+ damageamount = model->damageamount;
+ damagetype = model->damagetype;
+ damageinterval = model->damageinterval;
+ leakydamage = model->leakydamage;
+ Flags = (Flags&~SECF_SPECIALFLAGS) | (model->Flags & SECF_SPECIALFLAGS);
+}
+
+int sector_t::GetTerrain(int pos) const
+{
+ return terrainnum[pos] >= 0 ? terrainnum[pos] : TerrainTypes[GetTexture(pos)];
+}
+
+FArchive &operator<< (FArchive &arc, secspecial_t &p)
+{
+ if (SaveVersion < 4529)
+ {
+ int special;
+ arc << special;
+ sector_t sec;
+ P_InitSectorSpecial(&sec, special, true);
+ sec.GetSpecial(&p);
+ }
+ else
+ {
+ arc << p.special
+ << p.damageamount
+ << p.damagetype
+ << p.damageinterval
+ << p.leakydamage
+ << p.Flags;
+ }
+ return arc;
+}
+
+
+
bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const
{
bool copy = false;
diff --git a/src/p_setup.cpp b/src/p_setup.cpp
index 19f2e1b578..73c68d6c26 100644
--- a/src/p_setup.cpp
+++ b/src/p_setup.cpp
@@ -1512,7 +1512,6 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex)
ss->special = LittleShort(ms->special);
else // [RH] Translate to new sector special
ss->special = P_TranslateSectorSpecial (LittleShort(ms->special));
- ss->secretsector = !!(ss->special&SECRET_MASK);
tagManager.AddSectorTag(i, LittleShort(ms->tag));
ss->thinglist = NULL;
ss->touching_thinglist = NULL; // phares 3/14/98
@@ -1533,6 +1532,7 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex)
ss->gravity = 1.f; // [RH] Default sector gravity of 1.0
ss->ZoneNumber = 0xFFFF;
+ ss->terrainnum[sector_t::ceiling] = ss->terrainnum[sector_t::floor] = -1;
// [RH] Sectors default to white light with the default fade.
// If they are outside (have a sky ceiling), they use the outside fog.
@@ -4046,7 +4046,7 @@ void P_SetupLevel (const char *lumpname, int position)
{
if (mo->flags & MF_COUNTKILL)
{
- if (mo->Sector->special == dDamage_End)
+ if (mo->Sector->damageamount > 0 && (mo->Sector->Flags & (SECF_ENDGODMODE|SECF_ENDLEVEL)) == (SECF_ENDGODMODE|SECF_ENDLEVEL))
{
mo->ClearCounters();
}
diff --git a/src/p_sight.cpp b/src/p_sight.cpp
index 135698b8bc..2d465aab54 100644
--- a/src/p_sight.cpp
+++ b/src/p_sight.cpp
@@ -132,7 +132,7 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in)
{
int frontflag;
- frontflag = P_PointOnLineSide(sightthing->x, sightthing->y, li);
+ frontflag = P_PointOnLineSidePrecise(sightthing->x, sightthing->y, li);
//Check 3D FLOORS!
for(int i=1;i<=2;i++)
@@ -241,14 +241,14 @@ bool SightCheck::P_SightCheckLine (line_t *ld)
return true;
}
ld->validcount = validcount;
- if (P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace) ==
- P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace))
+ if (P_PointOnDivlineSidePrecise (ld->v1->x, ld->v1->y, &trace) ==
+ P_PointOnDivlineSidePrecise (ld->v2->x, ld->v2->y, &trace))
{
return true; // line isn't crossed
}
P_MakeDivline (ld, &dl);
- if (P_PointOnDivlineSide (trace.x, trace.y, &dl) ==
- P_PointOnDivlineSide (trace.x+trace.dx, trace.y+trace.dy, &dl))
+ if (P_PointOnDivlineSidePrecise (trace.x, trace.y, &dl) ==
+ P_PointOnDivlineSidePrecise (trace.x+trace.dx, trace.y+trace.dy, &dl))
{
return true; // line isn't crossed
}
diff --git a/src/p_slopes.cpp b/src/p_slopes.cpp
index c0b9b5ef0e..a3db265261 100644
--- a/src/p_slopes.cpp
+++ b/src/p_slopes.cpp
@@ -54,7 +54,7 @@ static void P_SlopeLineToPoint (int lineid, fixed_t x, fixed_t y, fixed_t z, boo
sector_t *sec;
secplane_t *plane;
- if (P_PointOnLineSide (x, y, line) == 0)
+ if (P_PointOnLineSidePrecise (x, y, line) == 0)
{
sec = line->frontsector;
}
@@ -363,7 +363,7 @@ static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt,
z3 = h3? *h3 : j==0? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling);
vt3.Z = FIXED2FLOAT(z3);
- if (P_PointOnLineSide(vertexes[vi3].x, vertexes[vi3].y, sec->lines[0]) == 0)
+ if (P_PointOnLineSidePrecise(vertexes[vi3].x, vertexes[vi3].y, sec->lines[0]) == 0)
{
vec1 = vt2 - vt3;
vec2 = vt1 - vt3;
diff --git a/src/p_spec.cpp b/src/p_spec.cpp
index 29aa731e1b..6b4ab479f6 100644
--- a/src/p_spec.cpp
+++ b/src/p_spec.cpp
@@ -62,6 +62,7 @@
#include "farchive.h"
#include "a_keys.h"
#include "c_dispatch.h"
+#include "r_sky.h"
// State.
#include "r_state.h"
@@ -71,7 +72,6 @@
#include "r_data/r_interpolate.h"
static FRandom pr_playerinspecialsector ("PlayerInSpecialSector");
-void P_SetupPortals();
EXTERN_CVAR(Bool, cl_predict_specials)
@@ -430,166 +430,62 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
{
// Falling, not all the way down yet?
sector = player->mo->Sector;
- if (player->mo->z != sector->floorplane.ZatPoint (player->mo->x, player->mo->y)
+ if (player->mo->z != sector->floorplane.ZatPoint(player->mo)
&& !player->mo->waterlevel)
{
return;
}
}
- int special = sector->special & ~SECRET_MASK;
-
// Has hit ground.
AInventory *ironfeet;
- // Allow subclasses. Better would be to implement it as armor and let that reduce
- // the damage as part of the normal damage procedure. Unfortunately, I don't have
- // different damage types yet, so that's not happening for now.
- for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
- {
- if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet)))
- break;
- }
-
- // [RH] Normal DOOM special or BOOM specialized?
- if (special >= dLight_Flicker && special <= 255)
- {
- switch (special)
- {
- case Sector_Heal:
- // CoD's healing sector
- if (!(level.time & 0x1f))
- P_GiveBody (player->mo, 1);
- break;
-
- case Damage_InstantDeath:
- // Strife's instant death sector
- P_DamageMobj (player->mo, NULL, NULL, 999, NAME_InstantDeath);
- break;
-
- case dDamage_Hellslime:
- // HELLSLIME DAMAGE
- if (ironfeet == NULL && !(level.time&0x1f))
- P_DamageMobj (player->mo, NULL, NULL, 10, NAME_Slime);
- break;
-
- case dDamage_Nukage:
- // NUKAGE DAMAGE
- case sLight_Strobe_Hurt:
- if (ironfeet == NULL && !(level.time&0x1f))
- P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Slime);
- break;
-
- case hDamage_Sludge:
- if (ironfeet == NULL && !(level.time&0x1f))
- P_DamageMobj (player->mo, NULL, NULL, 4, NAME_Slime);
- break;
-
- case dDamage_SuperHellslime:
- // SUPER HELLSLIME DAMAGE
- case dLight_Strobe_Hurt:
- // STROBE HURT
- if (ironfeet == NULL || pr_playerinspecialsector() < 5)
- {
- if (!(level.time&0x1f))
- P_DamageMobj (player->mo, NULL, NULL, 20, NAME_Slime);
- }
- break;
-
- case sDamage_Hellslime:
- if (ironfeet == NULL)
- player->hazardcount += 2;
- break;
-
- case sDamage_SuperHellslime:
- if (ironfeet == NULL)
- player->hazardcount += 4;
- break;
-
- case dDamage_End:
- // EXIT SUPER DAMAGE! (for E1M8 finale)
- player->cheats &= ~CF_GODMODE;
-
- if (!(level.time & 0x1f))
- P_DamageMobj (player->mo, NULL, NULL, 20, NAME_None);
-
- if (player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT)))
- G_ExitLevel(0, false);
- break;
-
- case dDamage_LavaWimpy:
- case dScroll_EastLavaDamage:
- if (!(level.time & 15))
- {
- P_DamageMobj(player->mo, NULL, NULL, 5, NAME_Fire);
- P_HitFloor(player->mo);
- }
- break;
-
- case dDamage_LavaHefty:
- if(!(level.time & 15))
- {
- P_DamageMobj(player->mo, NULL, NULL, 8, NAME_Fire);
- P_HitFloor(player->mo);
- }
- break;
-
- default:
- // [RH] Ignore unknown specials
- break;
- }
- }
- else
- {
- //jff 3/14/98 handle extended sector types for secrets and damage
- switch (special & DAMAGE_MASK)
- {
- case 0x000: // no damage
- break;
- case 0x100: // 2/5 damage per 31 ticks
- if (ironfeet == NULL && !(level.time&0x1f))
- P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Fire);
- break;
- case 0x200: // 5/10 damage per 31 ticks
- if (ironfeet == NULL && !(level.time&0x1f))
- P_DamageMobj (player->mo, NULL, NULL, 10, NAME_Slime);
- break;
- case 0x300: // 10/20 damage per 31 ticks
- if (ironfeet == NULL
- || pr_playerinspecialsector() < 5) // take damage even with suit
- {
- if (!(level.time&0x1f))
- P_DamageMobj (player->mo, NULL, NULL, 20, NAME_Slime);
- }
- break;
- }
- }
-
// [RH] Apply any customizable damage
- if (sector->damage)
+ if (sector->damageamount > 0)
{
- if (sector->damage < 20)
+ // Allow subclasses. Better would be to implement it as armor and let that reduce
+ // the damage as part of the normal damage procedure. Unfortunately, I don't have
+ // different damage types yet, so that's not happening for now.
+ for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
{
- if (ironfeet == NULL && !(level.time&0x1f))
- P_DamageMobj (player->mo, NULL, NULL, sector->damage, MODtoDamageType (sector->mod));
+ if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet)))
+ break;
}
- else if (sector->damage < 50)
+
+ if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE;
+ if ((ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage))
{
- if ((ironfeet == NULL || (pr_playerinspecialsector()<5))
- && !(level.time&0x1f))
+ if (sector->Flags & SECF_HAZARD)
{
- P_DamageMobj (player->mo, NULL, NULL, sector->damage, MODtoDamageType (sector->mod));
+ player->hazardcount += sector->damageamount;
+ player->hazardtype = sector->damagetype;
+ player->hazardinterval = sector->damageinterval;
+ }
+ else if (level.time % sector->damageinterval == 0)
+ {
+ P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype);
+ if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT)))
+ {
+ G_ExitLevel(0, false);
+ }
+ if (sector->Flags & SECF_DMGTERRAINFX)
+ {
+ P_HitWater(player->mo, sector, INT_MIN, INT_MIN, INT_MIN, false, true, true);
+ }
}
}
- else
+ }
+ else if (sector->damageamount < 0)
+ {
+ if (level.time % sector->damageinterval == 0)
{
- P_DamageMobj (player->mo, NULL, NULL, sector->damage, MODtoDamageType (sector->mod));
+ P_GiveBody(player->mo, -sector->damageamount, 100);
}
}
- if (sector->special & SECRET_MASK)
+ if (sector->isSecret())
{
- sector->special &= ~SECRET_MASK;
+ sector->ClearSecret();
P_GiveSecret(player->mo, true, true, int(sector - sectors));
}
}
@@ -611,7 +507,7 @@ static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type,
if (!(flags & DAMAGE_PLAYERS) && actor->player != NULL)
return;
- if (!(flags & DAMAGE_IN_AIR) && actor->z != sec->floorplane.ZatPoint(actor->x, actor->y) && !actor->waterlevel)
+ if (!(flags & DAMAGE_IN_AIR) && actor->z != sec->floorplane.ZatPoint(actor) && !actor->waterlevel)
return;
if (protectClass != NULL)
@@ -648,8 +544,8 @@ void P_SectorDamage(int tag, int amount, FName type, PClassActor *protectClass,
{
next = actor->snext;
// Only affect actors touching the 3D floor
- fixed_t z1 = sec->floorplane.ZatPoint(actor->x, actor->y);
- fixed_t z2 = sec->ceilingplane.ZatPoint(actor->x, actor->y);
+ fixed_t z1 = sec->floorplane.ZatPoint(actor);
+ fixed_t z2 = sec->ceilingplane.ZatPoint(actor);
if (z2 < z1)
{
// Account for Vavoom-style 3D floors
@@ -1013,10 +909,10 @@ static void SetupFloorPortal (AStackPoint *point)
{
NActorIterator it (NAME_LowerStackLookOnly, point->tid);
sector_t *Sector = point->Sector;
- Sector->FloorSkyBox = static_cast(it.Next());
- if (Sector->FloorSkyBox != NULL && Sector->FloorSkyBox->bAlways)
+ Sector->SkyBoxes[sector_t::floor] = static_cast(it.Next());
+ if (Sector->SkyBoxes[sector_t::floor] != NULL && Sector->SkyBoxes[sector_t::floor]->bAlways)
{
- Sector->FloorSkyBox->Mate = point;
+ Sector->SkyBoxes[sector_t::floor]->Mate = point;
if (Sector->GetAlpha(sector_t::floor) == OPAQUE)
Sector->SetAlpha(sector_t::floor, Scale (point->args[0], OPAQUE, 255));
}
@@ -1026,48 +922,15 @@ static void SetupCeilingPortal (AStackPoint *point)
{
NActorIterator it (NAME_UpperStackLookOnly, point->tid);
sector_t *Sector = point->Sector;
- Sector->CeilingSkyBox = static_cast(it.Next());
- if (Sector->CeilingSkyBox != NULL && Sector->CeilingSkyBox->bAlways)
+ Sector->SkyBoxes[sector_t::ceiling] = static_cast(it.Next());
+ if (Sector->SkyBoxes[sector_t::ceiling] != NULL && Sector->SkyBoxes[sector_t::ceiling]->bAlways)
{
- Sector->CeilingSkyBox->Mate = point;
+ Sector->SkyBoxes[sector_t::ceiling]->Mate = point;
if (Sector->GetAlpha(sector_t::ceiling) == OPAQUE)
Sector->SetAlpha(sector_t::ceiling, Scale (point->args[0], OPAQUE, 255));
}
}
-static bool SpreadCeilingPortal(AStackPoint *pt, fixed_t alpha, sector_t *sector)
-{
- bool fail = false;
- sector->validcount = validcount;
- for(int i=0; ilinecount; i++)
- {
- line_t *line = sector->lines[i];
- sector_t *backsector = sector == line->frontsector? line->backsector : line->frontsector;
- if (line->backsector == line->frontsector) continue;
- if (backsector == NULL) { fail = true; continue; }
- if (backsector->validcount == validcount) continue;
- if (backsector->CeilingSkyBox == pt) continue;
-
- // Check if the backside would map to the same visplane
- if (backsector->CeilingSkyBox != NULL) { fail = true; continue; }
- if (backsector->ceilingplane != sector->ceilingplane) { fail = true; continue; }
- if (backsector->lightlevel != sector->lightlevel) { fail = true; continue; }
- if (backsector->GetTexture(sector_t::ceiling) != sector->GetTexture(sector_t::ceiling)) { fail = true; continue; }
- if (backsector->GetXOffset(sector_t::ceiling) != sector->GetXOffset(sector_t::ceiling)) { fail = true; continue; }
- if (backsector->GetYOffset(sector_t::ceiling) != sector->GetYOffset(sector_t::ceiling)) { fail = true; continue; }
- if (backsector->GetXScale(sector_t::ceiling) != sector->GetXScale(sector_t::ceiling)) { fail = true; continue; }
- if (backsector->GetYScale(sector_t::ceiling) != sector->GetYScale(sector_t::ceiling)) { fail = true; continue; }
- if (backsector->GetAngle(sector_t::ceiling) != sector->GetAngle(sector_t::ceiling)) { fail = true; continue; }
- if (SpreadCeilingPortal(pt, alpha, backsector)) { fail = true; continue; }
- }
- if (!fail)
- {
- sector->CeilingSkyBox = pt;
- sector->SetAlpha(sector_t::ceiling, alpha);
- }
- return fail;
-}
-
void P_SetupPortals()
{
TThinkerIterator it;
@@ -1090,26 +953,64 @@ void P_SetupPortals()
}
}
-inline void SetPortal(sector_t *sector, int plane, AStackPoint *portal, fixed_t alpha)
+static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_t alpha)
{
// plane: 0=floor, 1=ceiling, 2=both
if (plane > 0)
{
- if (sector->CeilingSkyBox == NULL || !sector->CeilingSkyBox->bAlways)
+ if (sector->SkyBoxes[sector_t::ceiling] == NULL || !sector->SkyBoxes[sector_t::ceiling]->bAlways)
{
- sector->CeilingSkyBox = portal;
+ sector->SkyBoxes[sector_t::ceiling] = portal;
if (sector->GetAlpha(sector_t::ceiling) == OPAQUE)
sector->SetAlpha(sector_t::ceiling, alpha);
+
+ if (!portal->bAlways) sector->SetTexture(sector_t::ceiling, skyflatnum);
}
}
if (plane == 2 || plane == 0)
{
- if (sector->FloorSkyBox == NULL || !sector->FloorSkyBox->bAlways)
+ if (sector->SkyBoxes[sector_t::floor] == NULL || !sector->SkyBoxes[sector_t::floor]->bAlways)
{
- sector->FloorSkyBox = portal;
+ sector->SkyBoxes[sector_t::floor] = portal;
}
if (sector->GetAlpha(sector_t::floor) == OPAQUE)
sector->SetAlpha(sector_t::floor, alpha);
+
+ if (!portal->bAlways) sector->SetTexture(sector_t::floor, skyflatnum);
+ }
+}
+
+static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, fixed_t alpha, bool tolines)
+{
+ int s;
+ FSectorTagIterator itr(sectortag);
+ while ((s = itr.Next()) >= 0)
+ {
+ SetPortal(§ors[s], plane, origin, alpha);
+ }
+
+ for (int j=0;j= 0)
+ {
+ SetPortal(§ors[s], plane, origin, alpha);
+ }
+ }
+ }
}
}
@@ -1125,10 +1026,11 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha)
lines[i].args[2] == plane &&
lines[i].args[3] == 1)
{
- fixed_t x1 = (line->v1->x + line->v2->x) >> 1;
- fixed_t y1 = (line->v1->y + line->v2->y) >> 1;
- fixed_t x2 = (lines[i].v1->x + lines[i].v2->x) >> 1;
- fixed_t y2 = (lines[i].v1->y + lines[i].v2->y) >> 1;
+ // beware of overflows.
+ fixed_t x1 = fixed_t((SQWORD(line->v1->x) + SQWORD(line->v2->x)) >> 1);
+ fixed_t y1 = fixed_t((SQWORD(line->v1->y) + SQWORD(line->v2->y)) >> 1);
+ fixed_t x2 = fixed_t((SQWORD(lines[i].v1->x) + SQWORD(lines[i].v2->x)) >> 1);
+ fixed_t y2 = fixed_t((SQWORD(lines[i].v1->y) + SQWORD(lines[i].v2->y)) >> 1);
fixed_t alpha = Scale (lines[i].args[4], OPAQUE, 255);
AStackPoint *anchor = Spawn(x1, y1, 0, NO_REPLACE);
@@ -1142,42 +1044,261 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha)
reference->flags |= MF_JUSTATTACKED;
anchor->flags |= MF_JUSTATTACKED;
- int s;
- FSectorTagIterator itr(sectortag);
- while ((s = itr.Next()) >= 0)
- {
- SetPortal(§ors[s], plane, reference, alpha);
- }
-
- for (int j=0;j= 0)
- {
- SetPortal(§ors[s], plane, reference, alpha);
- }
- }
- }
- }
-
+ CopyPortal(sectortag, plane, reference, alpha, false);
return;
}
}
}
+// This searches the viewpoint's sector
+// for a skybox line special, gets its tag and transfers the skybox to all tagged sectors.
+void P_SpawnSkybox(ASkyViewpoint *origin)
+{
+ sector_t *Sector = origin->Sector;
+ if (Sector == NULL)
+ {
+ Printf("Sector not initialized for SkyCamCompat\n");
+ origin->Sector = Sector = P_PointInSector(origin->x, origin->y);
+ }
+ if (Sector)
+ {
+ line_t * refline = NULL;
+ for (short i = 0; i < Sector->linecount; i++)
+ {
+ refline = Sector->lines[i];
+ if (refline->special == Sector_SetPortal && refline->args[1] == 2)
+ {
+ // We found the setup linedef for this skybox, so let's use it for our init.
+ CopyPortal(refline->args[0], refline->args[2], origin, 0, true);
+ return;
+ }
+ }
+ }
+}
+
+
+
+//
+// P_SetSectorDamage
+//
+// Sets damage properties for one sector. Allows combination of original specials with explicit use of the damage properties
+//
+
+static void P_SetupSectorDamage(sector_t *sector, int damage, int interval, int leakchance, FName type, int flags)
+{
+ // Only set if damage is not yet initialized. This ensures that UDMF takes precedence over sector specials.
+ if (sector->damageamount == 0)
+ {
+ sector->damageamount = damage;
+ sector->damageinterval = MAX(1, interval);
+ sector->leakydamage = leakchance;
+ sector->damagetype = type;
+ sector->Flags = (sector->Flags & ~SECF_DAMAGEFLAGS) | (flags & SECF_DAMAGEFLAGS);
+ }
+}
+
+//
+// P_InitSectorSpecial
+//
+// Sets up everything derived from 'sector->special' for one sector
+// ('fromload' is necessary to allow conversion upon savegame load.)
+//
+
+void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers)
+{
+ // [RH] All secret sectors are marked with a BOOM-ish bitfield
+ if (sector->special & SECRET_MASK)
+ {
+ sector->Flags |= SECF_SECRET | SECF_WASSECRET;
+ level.total_secrets++;
+ }
+ if (sector->special & FRICTION_MASK)
+ {
+ sector->Flags |= SECF_FRICTION;
+ }
+ if (sector->special & PUSH_MASK)
+ {
+ sector->Flags |= SECF_PUSH;
+ }
+ if ((sector->special & DAMAGE_MASK) == 0x100)
+ {
+ P_SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0);
+ }
+ else if ((sector->special & DAMAGE_MASK) == 0x200)
+ {
+ P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0);
+ }
+ else if ((sector->special & DAMAGE_MASK) == 0x300)
+ {
+ P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
+ }
+ sector->special &= 0xff;
+
+ // [RH] Normal DOOM special or BOOM specialized?
+ bool keepspecial = false;
+ switch (sector->special)
+ {
+ case Light_Phased:
+ if (!nothinkers) new DPhased (sector, 48, 63 - (sector->lightlevel & 63));
+ break;
+
+ // [RH] Hexen-like phased lighting
+ case LightSequenceStart:
+ if (!nothinkers) new DPhased (sector);
+ break;
+
+ case dLight_Flicker:
+ if (!nothinkers) new DLightFlash (sector);
+ break;
+
+ case dLight_StrobeFast:
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
+ break;
+
+ case dLight_StrobeSlow:
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false);
+ break;
+
+ case dLight_Strobe_Hurt:
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
+ P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
+ break;
+
+ case dDamage_Hellslime:
+ P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0);
+ break;
+
+ case dDamage_Nukage:
+ P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0);
+ break;
+
+ case dLight_Glow:
+ if (!nothinkers) new DGlow (sector);
+ break;
+
+ case dSector_DoorCloseIn30:
+ P_SpawnDoorCloseIn30 (sector);
+ break;
+
+ case dDamage_End:
+ P_SetupSectorDamage(sector, 20, 32, 256, NAME_None, SECF_ENDGODMODE|SECF_ENDLEVEL);
+ break;
+
+ case dLight_StrobeSlowSync:
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true);
+ break;
+
+ case dLight_StrobeFastSync:
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, true);
+ break;
+
+ case dSector_DoorRaiseIn5Mins:
+ P_SpawnDoorRaiseIn5Mins (sector);
+ break;
+
+ case dFriction_Low:
+ sector->friction = FRICTION_LOW;
+ sector->movefactor = 0x269;
+ sector->Flags |= SECF_FRICTION;
+ break;
+
+ case dDamage_SuperHellslime:
+ P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
+ break;
+
+ case dLight_FireFlicker:
+ if (!nothinkers) new DFireFlicker (sector);
+ break;
+
+ case dDamage_LavaWimpy:
+ P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
+ break;
+
+ case dDamage_LavaHefty:
+ P_SetupSectorDamage(sector, 8, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
+ break;
+
+ case dScroll_EastLavaDamage:
+ P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
+ if (!nothinkers)
+ {
+ new DStrobe(sector, STROBEBRIGHT, FASTDARK, false);
+ new DScroller(DScroller::sc_floor, (-FRACUNIT / 2) << 3,
+ 0, -1, int(sector - sectors), 0);
+ }
+ keepspecial = true;
+ break;
+
+ case hDamage_Sludge:
+ P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, 0);
+ break;
+
+ case sLight_Strobe_Hurt:
+ P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0);
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
+ break;
+
+ case sDamage_Hellslime:
+ P_SetupSectorDamage(sector, 2, 32, 0, NAME_Slime, SECF_HAZARD);
+ break;
+
+ case Damage_InstantDeath:
+ // Strife's instant death sector
+ P_SetupSectorDamage(sector, TELEFRAG_DAMAGE, 1, 256, NAME_InstantDeath, 0);
+ break;
+
+ case sDamage_SuperHellslime:
+ P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, SECF_HAZARD);
+ break;
+
+ case Sector_Hidden:
+ sector->MoreFlags |= SECF_HIDDEN;
+ break;
+
+ case Sector_Heal:
+ // CoD's healing sector
+ P_SetupSectorDamage(sector, -1, 32, 0, NAME_None, 0);
+ break;
+
+ case Sky2:
+ sector->sky = PL_SKYFLAT;
+ break;
+
+ default:
+ if (sector->special >= Scroll_North_Slow &&
+ sector->special <= Scroll_SouthWest_Fast)
+ { // Hexen scroll special
+ static const char hexenScrollies[24][2] =
+ {
+ { 0, 1 }, { 0, 2 }, { 0, 4 },
+ { -1, 0 }, { -2, 0 }, { -4, 0 },
+ { 0, -1 }, { 0, -2 }, { 0, -4 },
+ { 1, 0 }, { 2, 0 }, { 4, 0 },
+ { 1, 1 }, { 2, 2 }, { 4, 4 },
+ { -1, 1 }, { -2, 2 }, { -4, 4 },
+ { -1, -1 }, { -2, -2 }, { -4, -4 },
+ { 1, -1 }, { 2, -2 }, { 4, -4 }
+ };
+
+
+ int i = sector->special - Scroll_North_Slow;
+ fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2);
+ fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2);
+ if (!nothinkers) new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0);
+ }
+ else if (sector->special >= Carry_East5 &&
+ sector->special <= Carry_East35)
+ { // Heretic scroll special
+ // Only east scrollers also scroll the texture
+ if (!nothinkers) new DScroller (DScroller::sc_floor,
+ (-FRACUNIT/2)<<(sector->special - Carry_East5),
+ 0, -1, int(sector-sectors), 0);
+ }
+ keepspecial = true;
+ break;
+ }
+ if (!keepspecial) sector->special = 0;
+}
//
// P_SpawnSpecials
@@ -1199,135 +1320,7 @@ void P_SpawnSpecials (void)
if (sector->special == 0)
continue;
- // [RH] All secret sectors are marked with a BOOM-ish bitfield
- if (sector->special & SECRET_MASK)
- level.total_secrets++;
-
- switch (sector->special & 0xff)
- {
- // [RH] Normal DOOM/Hexen specials. We clear off the special for lights
- // here instead of inside the spawners.
-
- case dLight_Flicker:
- // FLICKERING LIGHTS
- new DLightFlash (sector);
- sector->special &= 0xff00;
- break;
-
- case dLight_StrobeFast:
- // STROBE FAST
- new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
- sector->special &= 0xff00;
- break;
-
- case dLight_StrobeSlow:
- // STROBE SLOW
- new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false);
- sector->special &= 0xff00;
- break;
-
- case dLight_Strobe_Hurt:
- case sLight_Strobe_Hurt:
- // STROBE FAST/DEATH SLIME
- new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
- break;
-
- case dLight_Glow:
- // GLOWING LIGHT
- new DGlow (sector);
- sector->special &= 0xff00;
- break;
-
- case dSector_DoorCloseIn30:
- // DOOR CLOSE IN 30 SECONDS
- P_SpawnDoorCloseIn30 (sector);
- break;
-
- case dLight_StrobeSlowSync:
- // SYNC STROBE SLOW
- new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true);
- sector->special &= 0xff00;
- break;
-
- case dLight_StrobeFastSync:
- // SYNC STROBE FAST
- new DStrobe (sector, STROBEBRIGHT, FASTDARK, true);
- sector->special &= 0xff00;
- break;
-
- case dSector_DoorRaiseIn5Mins:
- // DOOR RAISE IN 5 MINUTES
- P_SpawnDoorRaiseIn5Mins (sector);
- break;
-
- case dLight_FireFlicker:
- // fire flickering
- new DFireFlicker (sector);
- sector->special &= 0xff00;
- break;
-
- case dFriction_Low:
- sector->friction = FRICTION_LOW;
- sector->movefactor = 0x269;
- sector->special &= 0xff00;
- sector->special |= FRICTION_MASK;
- break;
-
- // [RH] Hexen-like phased lighting
- case LightSequenceStart:
- new DPhased (sector);
- break;
-
- case Light_Phased:
- new DPhased (sector, 48, 63 - (sector->lightlevel & 63));
- break;
-
- case Sky2:
- sector->sky = PL_SKYFLAT;
- break;
-
- case dScroll_EastLavaDamage:
- new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
- new DScroller (DScroller::sc_floor, (-FRACUNIT/2)<<3,
- 0, -1, int(sector-sectors), 0);
- break;
-
- case Sector_Hidden:
- sector->MoreFlags |= SECF_HIDDEN;
- sector->special &= 0xff00;
- break;
-
- default:
- if ((sector->special & 0xff) >= Scroll_North_Slow &&
- (sector->special & 0xff) <= Scroll_SouthWest_Fast)
- { // Hexen scroll special
- static const char hexenScrollies[24][2] =
- {
- { 0, 1 }, { 0, 2 }, { 0, 4 },
- { -1, 0 }, { -2, 0 }, { -4, 0 },
- { 0, -1 }, { 0, -2 }, { 0, -4 },
- { 1, 0 }, { 2, 0 }, { 4, 0 },
- { 1, 1 }, { 2, 2 }, { 4, 4 },
- { -1, 1 }, { -2, 2 }, { -4, 4 },
- { -1, -1 }, { -2, -2 }, { -4, -4 },
- { 1, -1 }, { 2, -2 }, { 4, -4 }
- };
-
- int i = (sector->special & 0xff) - Scroll_North_Slow;
- fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2);
- fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2);
- new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0);
- }
- else if ((sector->special & 0xff) >= Carry_East5 &&
- (sector->special & 0xff) <= Carry_East35)
- { // Heretic scroll special
- // Only east scrollers also scroll the texture
- new DScroller (DScroller::sc_floor,
- (-FRACUNIT/2)<<((sector->special & 0xff) - Carry_East5),
- 0, -1, int(sector-sectors), 0);
- }
- break;
- }
+ P_InitSectorSpecial(sector, sector->special, false);
}
// Init other misc stuff
@@ -1336,6 +1329,13 @@ void P_SpawnSpecials (void)
P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs
P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs
+ TThinkerIterator it2;
+ ASkyCamCompat *pt2;
+ while ((pt2 = it2.Next()))
+ {
+ P_SpawnSkybox(pt2);
+ }
+
for (i = 0; i < numlines; i++)
{
switch (lines[i].special)
@@ -1449,8 +1449,24 @@ void P_SpawnSpecials (void)
FSectorTagIterator itr(lines[i].args[0]);
while ((s = itr.Next()) >= 0)
{
- sectors[s].damage = damage;
- sectors[s].mod = 0;//MOD_UNKNOWN;
+ sector_t *sec = §ors[s];
+ sec->damageamount = damage;
+ sec->damagetype = NAME_None;
+ if (sec->damageamount < 20)
+ {
+ sec->leakydamage = 0;
+ sec->damageinterval = 32;
+ }
+ else if (sec->damageamount < 50)
+ {
+ sec->leakydamage = 5;
+ sec->damageinterval = 32;
+ }
+ else
+ {
+ sec->leakydamage = 256;
+ sec->damageinterval = 1;
+ }
}
}
break;
@@ -2052,11 +2068,11 @@ void P_SetSectorFriction (int tag, int amount, bool alterFlag)
// can be enabled and disabled at will.
if (friction == ORIG_FRICTION)
{
- sectors[s].special &= ~FRICTION_MASK;
+ sectors[s].Flags &= ~SECF_FRICTION;
}
else
{
- sectors[s].special |= FRICTION_MASK;
+ sectors[s].Flags |= SECF_FRICTION;
}
}
}
@@ -2172,7 +2188,7 @@ void DPusher::Tick ()
// Be sure the special sector type is still turned on. If so, proceed.
// Else, bail out; the sector type has been changed on us.
- if (!(sec->special & PUSH_MASK))
+ if (!(sec->Flags & SECF_PUSH))
return;
// For constant pushers (wind/current) there are 3 situations:
@@ -2218,7 +2234,7 @@ void DPusher::Tick ()
{
int sx = m_X;
int sy = m_Y;
- int dist = P_AproxDistance (thing->x - sx,thing->y - sy);
+ int dist = thing->AproxDistance (sx, sy);
int speed = (m_Magnitude - ((dist>>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1);
// If speed <= 0, you're outside the effective radius. You also have
@@ -2226,7 +2242,7 @@ void DPusher::Tick ()
if ((speed > 0) && (P_CheckSight (thing, m_Source, SF_IGNOREVISIBILITY)))
{
- angle_t pushangle = R_PointToAngle2 (thing->x, thing->y, sx, sy);
+ angle_t pushangle = thing->AngleTo(sx, sy);
if (m_Source->GetClass()->TypeName == NAME_PointPusher)
pushangle += ANG180; // away
pushangle >>= ANGLETOFINESHIFT;
@@ -2265,7 +2281,7 @@ void DPusher::Tick ()
}
else // special water sector
{
- ht = hsec->floorplane.ZatPoint (thing->x, thing->y);
+ ht = hsec->floorplane.ZatPoint(thing);
if (thing->z > ht) // above ground
{
xspeed = m_Xmag; // full force
@@ -2294,7 +2310,7 @@ void DPusher::Tick ()
{ // special water sector
floor = &hsec->floorplane;
}
- if (thing->z > floor->ZatPoint (thing->x, thing->y))
+ if (thing->z > floor->ZatPoint(thing))
{ // above ground
xspeed = yspeed = 0; // no force
}
diff --git a/src/p_spec.h b/src/p_spec.h
index 37537b83a0..eb32f6fa02 100644
--- a/src/p_spec.h
+++ b/src/p_spec.h
@@ -158,6 +158,7 @@ bool PIT_PushThing (AActor *thing);
bool CheckIfExitIsGood (AActor *self, level_info_t *info);
// at map load
+void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers);
void P_SpawnSpecials (void);
// every tic
@@ -673,7 +674,7 @@ protected:
// [RH] Need these for BOOM-ish transferring ceilings
FTextureID m_Texture;
- int m_NewSpecial;
+ secspecial_t m_NewSpecial;
// ID
int m_Tag;
@@ -760,7 +761,7 @@ protected:
int m_Crush;
bool m_Hexencrush;
int m_Direction;
- int m_NewSpecial;
+ secspecial_t m_NewSpecial;
FTextureID m_Texture;
fixed_t m_FloorDestDist;
fixed_t m_Speed;
diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp
index 13c0cdbd04..8fbbf91b59 100644
--- a/src/p_teleport.cpp
+++ b/src/p_teleport.cpp
@@ -529,7 +529,7 @@ bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBO
int fudge = FUDGEFACTOR;
// Make sure we are on correct side of exit linedef.
- while (P_PointOnLineSide(x, y, l) != side && --fudge >= 0)
+ while (P_PointOnLineSidePrecise(x, y, l) != side && --fudge >= 0)
{
if (abs(l->dx) > abs(l->dy))
y -= (l->dx < 0) != side ? -1 : 1;
diff --git a/src/p_terrain.cpp b/src/p_terrain.cpp
index a1a9ea25b4..af8de5cab2 100644
--- a/src/p_terrain.cpp
+++ b/src/p_terrain.cpp
@@ -46,6 +46,7 @@
#include "s_sound.h"
#include "p_local.h"
#include "templates.h"
+#include "farchive.h"
// MACROS ------------------------------------------------------------------
@@ -121,7 +122,6 @@ static void ParseSplash (FScanner &sc);
static void ParseTerrain (FScanner &sc);
static void ParseFloor (FScanner &sc);
static int FindSplash (FName name);
-static int FindTerrain (FName name);
static void GenericParse (FScanner &sc, FGenericParse *parser, const char **keywords,
void *fields, const char *type, FName name);
static void ParseDamage (FScanner &sc, int keyword, void *fields);
@@ -427,7 +427,7 @@ void ParseTerrain (FScanner &sc)
sc.MustGetString ();
name = sc.String;
- terrainnum = (int)FindTerrain (name);
+ terrainnum = (int)P_FindTerrain (name);
if (terrainnum < 0)
{
FTerrainDef def;
@@ -637,7 +637,7 @@ static void ParseFloor (FScanner &sc)
return;
}
sc.MustGetString ();
- terrain = FindTerrain (sc.String);
+ terrain = P_FindTerrain (sc.String);
if (terrain == -1)
{
Printf ("Unknown terrain %s\n", sc.String);
@@ -657,7 +657,7 @@ static void ParseDefault (FScanner &sc)
int terrain;
sc.MustGetString ();
- terrain = FindTerrain (sc.String);
+ terrain = P_FindTerrain (sc.String);
if (terrain == -1)
{
Printf ("Unknown terrain %s\n", sc.String);
@@ -692,7 +692,7 @@ int FindSplash (FName name)
//
//==========================================================================
-int FindTerrain (FName name)
+int P_FindTerrain (FName name)
{
unsigned int i;
@@ -705,3 +705,26 @@ int FindTerrain (FName name)
}
return -1;
}
+
+void P_SerializeTerrain(FArchive &arc, int &terrainnum)
+{
+ FName val;
+ if (arc.IsStoring())
+ {
+ if (terrainnum < 0 || terrainnum >= (int)Terrains.Size())
+ {
+ val = NAME_Null;
+ }
+ else
+ {
+ val = Terrains[terrainnum].Name;
+ }
+ arc << val;
+ }
+ else
+ {
+ arc << val;
+ terrainnum = P_FindTerrain(val);
+
+ }
+}
diff --git a/src/p_terrain.h b/src/p_terrain.h
index 6bebe20ce3..3bc1836bf3 100644
--- a/src/p_terrain.h
+++ b/src/p_terrain.h
@@ -122,4 +122,8 @@ struct FTerrainDef
extern TArray Splashes;
extern TArray Terrains;
+class FArchive;
+int P_FindTerrain(FName name);
+void P_SerializeTerrain(FArchive &arc, int &terrainnum);
+
#endif //__P_TERRAIN_H__
diff --git a/src/p_things.cpp b/src/p_things.cpp
index 34ecb4912a..4e46f2b809 100644
--- a/src/p_things.cpp
+++ b/src/p_things.cpp
@@ -82,7 +82,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog,
}
while (spot != NULL)
{
- mobj = Spawn (kind, spot->x, spot->y, spot->z, ALLOW_REPLACE);
+ mobj = Spawn (kind, spot->X(), spot->Y(), spot->Z(), ALLOW_REPLACE);
if (mobj != NULL)
{
@@ -94,7 +94,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog,
mobj->angle = (angle != ANGLE_MAX ? angle : spot->angle);
if (fog)
{
- P_SpawnTeleportFog(mobj, spot->x, spot->y, spot->z + TELEFOGHEIGHT, false, true);
+ P_SpawnTeleportFog(mobj, spot->X(), spot->Y(), spot->Z() + TELEFOGHEIGHT, false, true);
}
if (mobj->flags & MF_SPECIAL)
mobj->flags |= MF_DROPPED; // Don't respawn
@@ -165,7 +165,7 @@ bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog)
if (source != NULL && target != NULL)
{
- return P_MoveThing(source, target->x, target->y, target->z, fog);
+ return P_MoveThing(source, target->X(), target->Y(), target->Z(), fog);
}
return false;
}
@@ -304,7 +304,8 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam
}
else
{
-nolead: mobj->angle = R_PointToAngle2 (mobj->x, mobj->y, targ->x, targ->y);
+nolead:
+ mobj->angle = mobj->AngleTo(targ);
aim.Resize (fspeed);
mobj->velx = fixed_t(aim[0]);
mobj->vely = fixed_t(aim[1]);
diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp
index db0c952cf3..9cfcbc0c25 100644
--- a/src/p_udmf.cpp
+++ b/src/p_udmf.cpp
@@ -47,6 +47,7 @@
#include "r_data/colormaps.h"
#include "w_wad.h"
#include "p_tags.h"
+#include "p_terrain.h"
//===========================================================================
//
@@ -1299,6 +1300,8 @@ public:
sec->prevsec = -1; // stair retriggering until build completes
sec->heightsec = NULL; // sector used to get floor and ceiling height
sec->sectornum = index;
+ sec->damageinterval = 32;
+ sec->terrainnum[sector_t::ceiling] = sec->terrainnum[sector_t::floor] = -1;
if (floordrop) sec->Flags = SECF_FLOORDROP;
// killough 3/7/98: end changes
@@ -1524,6 +1527,39 @@ public:
cp[3] = CheckFloat(key);
break;
+ case NAME_damageamount:
+ sec->damageamount = CheckInt(key);
+ break;
+
+ case NAME_damagetype:
+ sec->damagetype = CheckString(key);
+ break;
+
+ case NAME_damageinterval:
+ sec->damageinterval = CheckInt(key);
+ if (sec->damageinterval < 1) sec->damageinterval = 1;
+ break;
+
+ case NAME_leakiness:
+ sec->leakydamage = CheckInt(key);
+ break;
+
+ case NAME_damageterraineffect:
+ Flag(sec->Flags, SECF_DMGTERRAINFX, key);
+ break;
+
+ case NAME_damagehazard:
+ Flag(sec->Flags, SECF_HAZARD, key);
+ break;
+
+ case NAME_floorterrain:
+ sec->terrainnum[sector_t::floor] = P_FindTerrain(CheckString(key));
+ break;
+
+ case NAME_ceilingterrain:
+ sec->terrainnum[sector_t::ceiling] = P_FindTerrain(CheckString(key));
+ break;
+
case NAME_MoreIds:
// delay parsing of the tag string until parsing of the sector is complete
// This ensures that the ID is always the first tag in the list.
@@ -1550,7 +1586,15 @@ public:
}
}
- sec->secretsector = !!(sec->special&SECRET_MASK);
+ if (sec->damageamount == 0)
+ {
+ // If no damage is set, clear all other related properties so that they do not interfere
+ // with other means of setting them.
+ sec->damagetype = NAME_None;
+ sec->damageinterval = 0;
+ sec->leakydamage = 0;
+ sec->Flags &= ~SECF_DAMAGEFLAGS;
+ }
// Reset the planes to their defaults if not all of the plane equation's parameters were found.
if (fplaneflags != 15)
@@ -1594,10 +1638,10 @@ public:
{
// [RH] Sectors default to white light with the default fade.
// If they are outside (have a sky ceiling), they use the outside fog.
- if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special&0xff) == Sector_Outside))
+ if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special & 0xff) == Sector_Outside))
{
if (fogMap == NULL)
- fogMap = GetSpecialLights (PalEntry (255,255,255), level.outsidefog, 0);
+ fogMap = GetSpecialLights(PalEntry(255, 255, 255), level.outsidefog, 0);
sec->ColorMap = fogMap;
}
else
@@ -1610,9 +1654,9 @@ public:
else
{
if (lightcolor == -1) lightcolor = PalEntry(255,255,255);
- if (fadecolor == -1)
+ if (fadecolor == -1)
{
- if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special&0xff) == Sector_Outside))
+ if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special & 0xff) == Sector_Outside))
fadecolor = level.outsidefog;
else
fadecolor = level.fadeto;
diff --git a/src/p_user.cpp b/src/p_user.cpp
index 6e0987aa53..450b330e65 100644
--- a/src/p_user.cpp
+++ b/src/p_user.cpp
@@ -361,6 +361,8 @@ player_t &player_t::operator=(const player_t &p)
damagecount = p.damagecount;
bonuscount = p.bonuscount;
hazardcount = p.hazardcount;
+ hazardtype = p.hazardtype;
+ hazardinterval = p.hazardinterval;
poisoncount = p.poisoncount;
poisontype = p.poisontype;
poisonpaintype = p.poisonpaintype;
@@ -2625,10 +2627,8 @@ void P_PlayerThink (player_t *player)
if (!(player->cheats & CF_PREDICTING))
{
P_PlayerOnSpecial3DFloor (player);
- if (player->mo->Sector->special || player->mo->Sector->damage)
- {
- P_PlayerInSpecialSector (player);
- }
+ P_PlayerInSpecialSector (player);
+
if (player->mo->z <= player->mo->Sector->floorplane.ZatPoint(
player->mo->x, player->mo->y) ||
player->mo->waterlevel)
@@ -2687,8 +2687,8 @@ void P_PlayerThink (player_t *player)
if (player->hazardcount)
{
player->hazardcount--;
- if (!(level.time & 31) && player->hazardcount > 16*TICRATE)
- P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Slime);
+ if (!(level.time % player->hazardinterval) && player->hazardcount > 16*TICRATE)
+ P_DamageMobj (player->mo, NULL, NULL, 5, player->hazardtype);
}
if (player->poisoncount && !(level.time & 15))
@@ -3101,7 +3101,12 @@ void player_t::Serialize (FArchive &arc)
<< air_finished
<< turnticks
<< oldbuttons;
- bool IsBot;
+ if (SaveVersion >= 4929)
+ {
+ arc << hazardtype
+ << hazardinterval;
+ }
+ bool IsBot = false;
if (SaveVersion >= 4514)
{
arc << Bot;
diff --git a/src/po_man.cpp b/src/po_man.cpp
index 60627e4f3c..fb1d12519d 100644
--- a/src/po_man.cpp
+++ b/src/po_man.cpp
@@ -1231,15 +1231,15 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd)
// Best use the one facing the player and ignore the back side.
if (ld->sidedef[1] != NULL)
{
- int side = P_PointOnLineSide(mobj->x, mobj->y, ld);
+ int side = P_PointOnLineSidePrecise(mobj->x, mobj->y, ld);
if (ld->sidedef[side] != sd)
{
continue;
}
// [BL] See if we hit below the floor/ceiling of the poly.
else if(!performBlockingThrust && (
- mobj->z < ld->sidedef[!side]->sector->GetSecPlane(sector_t::floor).ZatPoint(mobj->x, mobj->y) ||
- mobj->z + mobj->height > ld->sidedef[!side]->sector->GetSecPlane(sector_t::ceiling).ZatPoint(mobj->x, mobj->y)
+ mobj->z < ld->sidedef[!side]->sector->GetSecPlane(sector_t::floor).ZatPoint(mobj) ||
+ mobj->z + mobj->height > ld->sidedef[!side]->sector->GetSecPlane(sector_t::ceiling).ZatPoint(mobj)
))
{
performBlockingThrust = true;
@@ -1533,11 +1533,15 @@ static void IterFindPolySides (FPolyObj *po, side_t *side)
//
//==========================================================================
+static int STACK_ARGS posicmp(const void *a, const void *b)
+{
+ return (*(const side_t **)a)->linedef->args[1] - (*(const side_t **)b)->linedef->args[1];
+}
+
static void SpawnPolyobj (int index, int tag, int type)
{
unsigned int ii;
int i;
- int j;
FPolyObj *po = &polyobjs[index];
for (ii = 0; ii < KnownPolySides.Size(); ++ii)
@@ -1577,59 +1581,24 @@ static void SpawnPolyobj (int index, int tag, int type)
// didn't find a polyobj through PO_LINE_START
TArray polySideList;
unsigned int psIndexOld;
- for (j = 1; j < PO_MAXPOLYSEGS; j++)
- {
- psIndexOld = po->Sidedefs.Size();
- for (ii = 0; ii < KnownPolySides.Size(); ++ii)
- {
- i = KnownPolySides[ii];
+ psIndexOld = po->Sidedefs.Size();
- if (i >= 0 &&
- sides[i].linedef->special == Polyobj_ExplicitLine &&
- sides[i].linedef->args[0] == tag)
- {
- if (!sides[i].linedef->args[1])
- {
- I_Error ("SpawnPolyobj: Explicit line missing order number (probably %d) in poly %d.\n",
- j+1, tag);
- }
- if (sides[i].linedef->args[1] == j)
- {
- po->Sidedefs.Push (&sides[i]);
- }
- }
- }
- // Clear out any specials for these segs...we cannot clear them out
- // in the above loop, since we aren't guaranteed one seg per linedef.
- for (ii = 0; ii < KnownPolySides.Size(); ++ii)
+ for (ii = 0; ii < KnownPolySides.Size(); ++ii)
+ {
+ i = KnownPolySides[ii];
+
+ if (i >= 0 &&
+ sides[i].linedef->special == Polyobj_ExplicitLine &&
+ sides[i].linedef->args[0] == tag)
{
- i = KnownPolySides[ii];
- if (i >= 0 &&
- sides[i].linedef->special == Polyobj_ExplicitLine &&
- sides[i].linedef->args[0] == tag && sides[i].linedef->args[1] == j)
+ if (!sides[i].linedef->args[1])
{
- sides[i].linedef->special = 0;
- sides[i].linedef->args[0] = 0;
- KnownPolySides[ii] = -1;
- }
- }
- if (po->Sidedefs.Size() == psIndexOld)
- { // Check if an explicit line order has been skipped.
- // A line has been skipped if there are any more explicit
- // lines with the current tag value. [RH] Can this actually happen?
- for (ii = 0; ii < KnownPolySides.Size(); ++ii)
- {
- i = KnownPolySides[ii];
- if (i >= 0 &&
- sides[i].linedef->special == Polyobj_ExplicitLine &&
- sides[i].linedef->args[0] == tag)
- {
- I_Error ("SpawnPolyobj: Missing explicit line %d for poly %d\n",
- j, tag);
- }
+ I_Error("SpawnPolyobj: Explicit line missing order number in poly %d, linedef %d.\n", tag, int(sides[i].linedef - lines));
}
+ po->Sidedefs.Push (&sides[i]);
}
}
+ qsort(&po->Sidedefs[0], po->Sidedefs.Size(), sizeof(po->Sidedefs[0]), posicmp);
if (po->Sidedefs.Size() > 0)
{
po->crush = (type != SMT_PolySpawn) ? 3 : 0;
diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h
index 545540b2fd..c0986b90af 100644
--- a/src/posix/cocoa/i_common.h
+++ b/src/posix/cocoa/i_common.h
@@ -31,6 +31,9 @@
**
*/
+#ifndef COCOA_I_COMMON_INCLUDED
+#define COCOA_I_COMMON_INCLUDED
+
#import
@@ -50,12 +53,23 @@ struct RenderBufferOptions
extern RenderBufferOptions rbOpts;
+// Version of AppKit framework we are interested in
+// The following values are needed to build with earlier SDKs
+
+#define AppKit10_4 824
+#define AppKit10_5 949
+#define AppKit10_6 1038
+#define AppKit10_7 1138
+
+
+@interface NSWindow(ExitAppOnClose)
+- (void)exitAppOnClose;
+@end
+
+
inline bool I_IsHiDPISupported()
{
- // The following value shoud be equal to NSAppKitVersionNumber10_7
- // and it's hard-coded in order to build on earlier SDKs
-
- return NSAppKitVersionNumber >= 1138;
+ return NSAppKitVersionNumber >= AppKit10_7;
}
void I_ProcessEvent(NSEvent* event);
@@ -79,6 +93,7 @@ typedef float CGFloat;
// From HIToolbox/Events.h
enum
{
+ kVK_ANSI_F = 0x03,
kVK_Return = 0x24,
kVK_Tab = 0x30,
kVK_Space = 0x31,
@@ -168,3 +183,5 @@ typedef NSInteger NSApplicationActivationPolicy;
@end
#endif // prior to 10.7
+
+#endif // COCOA_I_COMMON_INCLUDED
diff --git a/src/posix/cocoa/i_input.mm b/src/posix/cocoa/i_input.mm
index 5e0c5f1c85..3bbf42a9ad 100644
--- a/src/posix/cocoa/i_input.mm
+++ b/src/posix/cocoa/i_input.mm
@@ -57,6 +57,8 @@ CVAR(Bool, use_mouse, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, m_noprescale, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, m_filter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
+CVAR(Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
+
CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)
{
if (self < 0)
@@ -542,6 +544,16 @@ void ProcessKeyboardEvent(NSEvent* theEvent)
return;
}
+ if (k_allowfullscreentoggle
+ && (kVK_ANSI_F == keyCode)
+ && (NSCommandKeyMask & [theEvent modifierFlags])
+ && (NSKeyDown == [theEvent type])
+ && ![theEvent isARepeat])
+ {
+ ToggleFullscreen = !ToggleFullscreen;
+ return;
+ }
+
if (GUICapture)
{
ProcessKeyboardEventInMenu(theEvent);
diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm
index 05a8081f6c..2f65254a98 100644
--- a/src/posix/cocoa/i_main.mm
+++ b/src/posix/cocoa/i_main.mm
@@ -47,6 +47,7 @@
#include "i_system.h"
#include "m_argv.h"
#include "s_sound.h"
+#include "st_console.h"
#include "version.h"
#undef Class
@@ -125,18 +126,7 @@ void Mac_I_FatalError(const char* const message)
{
I_SetMainWindowVisible(false);
- const CFStringRef errorString = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault,
- message, kCFStringEncodingASCII, kCFAllocatorNull);
-
- if (NULL != errorString)
- {
- CFOptionFlags dummy;
-
- CFUserNotificationDisplayAlert( 0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL,
- CFSTR("Fatal Error"), errorString, CFSTR("Exit"), NULL, NULL, &dummy);
-
- CFRelease(errorString);
- }
+ FConsoleWindow::GetInstance().ShowFatalError(message);
}
@@ -315,6 +305,9 @@ ApplicationController* appCtrl;
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSDefaultRunLoopMode];
+ FConsoleWindow::CreateInstance();
+ atterm(FConsoleWindow::DeleteInstance);
+
exit(OriginalMain(s_argc, s_argv));
}
diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm
new file mode 100644
index 0000000000..498498d946
--- /dev/null
+++ b/src/posix/cocoa/i_system.mm
@@ -0,0 +1,378 @@
+/*
+ ** i_system.mm
+ **
+ **---------------------------------------------------------------------------
+ ** Copyright 2012-2015 Alexey Lysiuk
+ ** All rights reserved.
+ **
+ ** Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions
+ ** are met:
+ **
+ ** 1. Redistributions of source code must retain the above copyright
+ ** notice, this list of conditions and the following disclaimer.
+ ** 2. Redistributions in binary form must reproduce the above copyright
+ ** notice, this list of conditions and the following disclaimer in the
+ ** documentation and/or other materials provided with the distribution.
+ ** 3. The name of the author may not be used to endorse or promote products
+ ** derived from this software without specific prior written permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **---------------------------------------------------------------------------
+ **
+ */
+
+#include "i_common.h"
+
+#include
+#include
+#include
+
+#include "d_ticcmd.h"
+#include "doomdef.h"
+#include "doomerrors.h"
+#include "doomstat.h"
+#include "g_game.h"
+#include "gameconfigfile.h"
+#include "i_sound.h"
+#include "i_system.h"
+#include "st_console.h"
+#include "v_text.h"
+#include "x86.h"
+
+
+EXTERN_CVAR(String, language)
+
+DWORD LanguageIDs[4];
+
+
+int (*I_GetTime)(bool saveMS);
+int (*I_WaitForTic)(int);
+void (*I_FreezeTime)(bool frozen);
+
+
+void I_Tactile(int /*on*/, int /*off*/, int /*total*/)
+{
+}
+
+
+ticcmd_t* I_BaseTiccmd()
+{
+ static ticcmd_t emptycmd;
+ return &emptycmd;
+}
+
+
+void I_WaitVBL(const int count)
+{
+ // I_WaitVBL is never used to actually synchronize to the
+ // vertical blank. Instead, it's used for delay purposes.
+ usleep(1000000 * count / 70);
+}
+
+
+//
+// SetLanguageIDs
+//
+void SetLanguageIDs()
+{
+ size_t langlen = strlen(language);
+
+ DWORD lang = (langlen < 2 || langlen > 3)
+ ? MAKE_ID('e', 'n', 'u', '\0')
+ : MAKE_ID(language[0], language[1], language[2], '\0');
+
+ LanguageIDs[3] = LanguageIDs[2] = LanguageIDs[1] = LanguageIDs[0] = lang;
+}
+
+
+void I_InitTimer();
+void I_ShutdownTimer();
+
+void I_Init(void)
+{
+ CheckCPUID(&CPU);
+ DumpCPUInfo(&CPU);
+
+ atterm(I_ShutdownSound);
+ I_InitSound();
+ I_InitTimer();
+}
+
+static int has_exited;
+
+void I_Quit()
+{
+ has_exited = 1; // Prevent infinitely recursive exits -- killough
+
+ if (demorecording)
+ {
+ G_CheckDemoStatus();
+ }
+
+ C_DeinitConsole();
+
+ I_ShutdownTimer();
+}
+
+
+extern FILE* Logfile;
+bool gameisdead;
+
+void STACK_ARGS I_FatalError(const char* const error, ...)
+{
+ static bool alreadyThrown = false;
+ gameisdead = true;
+
+ if (!alreadyThrown) // ignore all but the first message -- killough
+ {
+ alreadyThrown = true;
+
+ char errortext[MAX_ERRORTEXT];
+ int index;
+ va_list argptr;
+ va_start(argptr, error);
+ index = vsnprintf(errortext, MAX_ERRORTEXT, error, argptr);
+ va_end(argptr);
+
+ extern void Mac_I_FatalError(const char*);
+ Mac_I_FatalError(errortext);
+
+ // Record error to log (if logging)
+ if (Logfile)
+ {
+ fprintf(Logfile, "\n**** DIED WITH FATAL ERROR:\n%s\n", errortext);
+ fflush(Logfile);
+ }
+
+ fprintf(stderr, "%s\n", errortext);
+ exit(-1);
+ }
+
+ if (!has_exited) // If it hasn't exited yet, exit now -- killough
+ {
+ has_exited = 1; // Prevent infinitely recursive exits -- killough
+ exit(-1);
+ }
+}
+
+void STACK_ARGS I_Error(const char* const error, ...)
+{
+ va_list argptr;
+ char errortext[MAX_ERRORTEXT];
+
+ va_start(argptr, error);
+ vsnprintf(errortext, MAX_ERRORTEXT, error, argptr);
+ va_end(argptr);
+
+ throw CRecoverableError(errortext);
+}
+
+
+void I_SetIWADInfo()
+{
+}
+
+
+void I_PrintStr(const char* const message)
+{
+ FConsoleWindow::GetInstance().AddText(message);
+
+ // Strip out any color escape sequences before writing to output
+ char* const copy = new char[strlen(message) + 1];
+ const char* srcp = message;
+ char* dstp = copy;
+
+ while ('\0' != *srcp)
+ {
+ if (TEXTCOLOR_ESCAPE == *srcp)
+ {
+ if ('\0' != srcp[1])
+ {
+ srcp += 2;
+ }
+ else
+ {
+ break;
+ }
+ }
+ else if (0x1d == *srcp || 0x1f == *srcp) // Opening and closing bar character
+ {
+ *dstp++ = '-';
+ *srcp++;
+ }
+ else if (0x1e == *srcp) // Middle bar character
+ {
+ *dstp++ = '=';
+ *srcp++;
+ }
+ else
+ {
+ *dstp++ = *srcp++;
+ }
+ }
+
+ *dstp = '\0';
+
+ fputs(copy, stdout);
+ delete[] copy;
+ fflush(stdout);
+}
+
+
+int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad)
+{
+ if (!showwin)
+ {
+ return defaultiwad;
+ }
+
+ I_SetMainWindowVisible(false);
+
+ extern int I_PickIWad_Cocoa(WadStuff*, int, bool, int);
+ const int result = I_PickIWad_Cocoa(wads, numwads, showwin, defaultiwad);
+
+ I_SetMainWindowVisible(true);
+
+ return result;
+}
+
+
+bool I_WriteIniFailed()
+{
+ printf("The config file %s could not be saved:\n%s\n", GameConfig->GetPathName(), strerror(errno));
+ return false; // return true to retry
+}
+
+
+static const char *pattern;
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080
+static int matchfile(struct dirent *ent)
+#else
+static int matchfile(const struct dirent *ent)
+#endif
+{
+ return fnmatch(pattern, ent->d_name, FNM_NOESCAPE) == 0;
+}
+
+void* I_FindFirst(const char* const filespec, findstate_t* const fileinfo)
+{
+ FString dir;
+
+ const char* const slash = strrchr(filespec, '/');
+
+ if (slash)
+ {
+ pattern = slash+1;
+ dir = FString(filespec, slash - filespec + 1);
+ }
+ else
+ {
+ pattern = filespec;
+ dir = ".";
+ }
+
+ fileinfo->current = 0;
+ fileinfo->count = scandir(dir.GetChars(), &fileinfo->namelist, matchfile, alphasort);
+
+ if (fileinfo->count > 0)
+ {
+ return fileinfo;
+ }
+
+ return (void*)-1;
+}
+
+int I_FindNext(void* const handle, findstate_t* const fileinfo)
+{
+ findstate_t* const state = static_cast(handle);
+
+ if (state->current < fileinfo->count)
+ {
+ return ++state->current < fileinfo->count ? 0 : -1;
+ }
+
+ return -1;
+}
+
+int I_FindClose(void* const handle)
+{
+ findstate_t* const state = static_cast(handle);
+
+ if (handle != (void*)-1 && state->count > 0)
+ {
+ for (int i = 0; i < state->count; ++i)
+ {
+ free(state->namelist[i]);
+ }
+
+ free(state->namelist);
+ state->namelist = NULL;
+ state->count = 0;
+ }
+
+ return 0;
+}
+
+int I_FindAttr(findstate_t* const fileinfo)
+{
+ dirent* const ent = fileinfo->namelist[fileinfo->current];
+ struct stat buf;
+
+ if (stat(ent->d_name, &buf) == 0)
+ {
+ return S_ISDIR(buf.st_mode) ? FA_DIREC : 0;
+ }
+
+ return 0;
+}
+
+
+void I_PutInClipboard(const char* const string)
+{
+ NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard];
+ NSString* const stringType = NSStringPboardType;
+ NSArray* const types = [NSArray arrayWithObjects:stringType, nil];
+ NSString* const content = [NSString stringWithUTF8String:string];
+
+ [pasteBoard declareTypes:types
+ owner:nil];
+ [pasteBoard setString:content
+ forType:stringType];
+}
+
+FString I_GetFromClipboard(bool returnNothing)
+{
+ if (returnNothing)
+ {
+ return FString();
+ }
+
+ NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard];
+ NSString* const value = [pasteBoard stringForType:NSStringPboardType];
+
+ return FString([value UTF8String]);
+}
+
+
+unsigned int I_MakeRNGSeed()
+{
+ return static_cast(arc4random());
+}
+
+
+TArray I_GetGogPaths()
+{
+ // GOG's Doom games are Windows only at the moment
+ return TArray();
+}
diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm
index 3fc2b2aed2..1a535c0880 100644
--- a/src/posix/cocoa/i_video.mm
+++ b/src/posix/cocoa/i_video.mm
@@ -47,6 +47,7 @@
#include "m_argv.h"
#include "r_renderer.h"
#include "r_swrenderer.h"
+#include "st_console.h"
#include "stats.h"
#include "textures.h"
#include "v_palette.h"
@@ -58,6 +59,18 @@
#undef Class
+@implementation NSWindow(ExitAppOnClose)
+
+- (void)exitAppOnClose
+{
+ NSButton* closeButton = [self standardWindowButton:NSWindowCloseButton];
+ [closeButton setAction:@selector(terminate:)];
+ [closeButton setTarget:NSApp];
+}
+
+@end
+
+
EXTERN_CVAR(Bool, ticker )
EXTERN_CVAR(Bool, vid_vsync)
EXTERN_CVAR(Bool, vid_hidpi)
@@ -407,7 +420,7 @@ CocoaVideo::CocoaVideo(const int multisample)
attributes[i++] = NSOpenGLPFAStencilSize;
attributes[i++] = NSOpenGLPixelFormatAttribute(8);
- if (!vid_autoswitch)
+ if (NSAppKitVersionNumber >= AppKit10_5 && !vid_autoswitch)
{
attributes[i++] = NSOpenGLPFAAllowOfflineRenderers;
}
@@ -433,6 +446,8 @@ CocoaVideo::CocoaVideo(const int multisample)
[[glView openGLContext] makeCurrentContext];
[m_window setContentView:glView];
+
+ FConsoleWindow::GetInstance().Show(false);
}
void CocoaVideo::StartModeIterator(const int bits, const bool fullscreen)
@@ -555,16 +570,15 @@ void CocoaVideo::SetWindowVisible(bool visible)
{
[video->m_window orderOut:nil];
}
+
+ I_SetNativeMouse(!visible);
}
}
static bool HasModernFullscreenAPI()
{
- // The following value shoud be equal to NSAppKitVersionNumber10_6
- // and it's hard-coded in order to build on earlier SDKs
-
- return NSAppKitVersionNumber >= 1038;
+ return NSAppKitVersionNumber >= AppKit10_6;
}
void CocoaVideo::SetStyleMask(const NSUInteger styleMask)
@@ -625,7 +639,7 @@ void CocoaVideo::SetFullscreenMode(const int width, const int height)
[m_window setHidesOnDeactivate:YES];
}
- [m_window setFrame:displayRect display:YES];
+ [m_window setFrame:screenFrame display:YES];
[m_window setFrameOrigin:NSMakePoint(0.0f, 0.0f)];
}
@@ -662,10 +676,7 @@ void CocoaVideo::SetWindowedMode(const int width, const int height)
[m_window setContentSize:windowSize];
[m_window center];
-
- NSButton* closeButton = [m_window standardWindowButton:NSWindowCloseButton];
- [closeButton setAction:@selector(terminate:)];
- [closeButton setTarget:NSApp];
+ [m_window exitAppOnClose];
}
void CocoaVideo::SetMode(const int width, const int height, const bool fullscreen, const bool hiDPI)
@@ -1211,7 +1222,7 @@ bool I_SetCursor(FTexture* cursorpic)
// Create image from representation and set it as cursor
NSData* imageData = [bitmapImageRep representationUsingType:NSPNGFileType
- properties:nil];
+ properties:[NSDictionary dictionary]];
NSImage* cursorImage = [[NSImage alloc] initWithData:imageData];
cursor = [[NSCursor alloc] initWithImage:cursorImage
@@ -1231,10 +1242,7 @@ NSSize I_GetContentViewSize(const NSWindow* const window)
const NSView* const view = [window contentView];
const NSSize frameSize = [view frame].size;
- // TODO: figure out why [NSView frame] returns different values in "fullscreen" and in window
- // In "fullscreen" the result is multiplied by [NSScreen backingScaleFactor], but not in window
-
- return (vid_hidpi && !fullscreen)
+ return (vid_hidpi)
? [view convertSizeToBacking:frameSize]
: frameSize;
}
@@ -1242,5 +1250,4 @@ NSSize I_GetContentViewSize(const NSWindow* const window)
void I_SetMainWindowVisible(bool visible)
{
CocoaVideo::SetWindowVisible(visible);
- I_SetNativeMouse(!visible);
}
diff --git a/src/posix/cocoa/st_console.h b/src/posix/cocoa/st_console.h
new file mode 100644
index 0000000000..6b6f018207
--- /dev/null
+++ b/src/posix/cocoa/st_console.h
@@ -0,0 +1,94 @@
+/*
+ ** st_console.h
+ **
+ **---------------------------------------------------------------------------
+ ** Copyright 2015 Alexey Lysiuk
+ ** All rights reserved.
+ **
+ ** Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions
+ ** are met:
+ **
+ ** 1. Redistributions of source code must retain the above copyright
+ ** notice, this list of conditions and the following disclaimer.
+ ** 2. Redistributions in binary form must reproduce the above copyright
+ ** notice, this list of conditions and the following disclaimer in the
+ ** documentation and/or other materials provided with the distribution.
+ ** 3. The name of the author may not be used to endorse or promote products
+ ** derived from this software without specific prior written permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **---------------------------------------------------------------------------
+ **
+ */
+
+#ifndef COCOA_ST_CONSOLE_INCLUDED
+#define COCOA_ST_CONSOLE_INCLUDED
+
+@class NSButton;
+@class NSProgressIndicator;
+@class NSScrollView;
+@class NSTextField;
+@class NSTextView;
+@class NSView;
+@class NSWindow;
+
+struct PalEntry;
+
+
+class FConsoleWindow
+{
+public:
+ static FConsoleWindow& GetInstance();
+
+ static void CreateInstance();
+ static void DeleteInstance();
+
+ void Show(bool visible);
+ void ShowFatalError(const char* message);
+
+ void AddText(const char* message);
+
+ void SetTitleText();
+ void SetProgressBar(bool visible);
+
+ // FStartupScreen functionality
+ void Progress(int current, int maximum);
+ void NetInit(const char* message, int playerCount);
+ void NetProgress(int count);
+ void NetDone();
+
+private:
+ NSWindow* m_window;
+ NSTextView* m_textView;
+ NSScrollView* m_scrollView;
+ NSProgressIndicator* m_progressBar;
+
+ NSView* m_netView;
+ NSTextField* m_netMessageText;
+ NSTextField* m_netCountText;
+ NSProgressIndicator* m_netProgressBar;
+ NSButton* m_netAbortButton;
+
+ unsigned int m_characterCount;
+
+ int m_netCurPos;
+ int m_netMaxPos;
+
+ FConsoleWindow();
+
+ void ExpandTextView(float height);
+
+ void AddText(const PalEntry& color, const char* message);
+};
+
+#endif // COCOA_ST_CONSOLE_INCLUDED
diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm
new file mode 100644
index 0000000000..e952d22d6b
--- /dev/null
+++ b/src/posix/cocoa/st_console.mm
@@ -0,0 +1,499 @@
+/*
+ ** st_console.mm
+ **
+ **---------------------------------------------------------------------------
+ ** Copyright 2015 Alexey Lysiuk
+ ** All rights reserved.
+ **
+ ** Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions
+ ** are met:
+ **
+ ** 1. Redistributions of source code must retain the above copyright
+ ** notice, this list of conditions and the following disclaimer.
+ ** 2. Redistributions in binary form must reproduce the above copyright
+ ** notice, this list of conditions and the following disclaimer in the
+ ** documentation and/or other materials provided with the distribution.
+ ** 3. The name of the author may not be used to endorse or promote products
+ ** derived from this software without specific prior written permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **---------------------------------------------------------------------------
+ **
+ */
+
+#include "i_common.h"
+
+#include "d_main.h"
+#include "i_system.h"
+#include "st_console.h"
+#include "v_text.h"
+#include "version.h"
+
+
+static NSColor* RGB(const BYTE red, const BYTE green, const BYTE blue)
+{
+ return [NSColor colorWithCalibratedRed:red / 255.0f
+ green:green / 255.0f
+ blue:blue / 255.0f
+ alpha:1.0f];
+}
+
+static NSColor* RGB(const PalEntry& color)
+{
+ return RGB(color.r, color.g, color.b);
+}
+
+static NSColor* RGB(const DWORD color)
+{
+ return RGB(PalEntry(color));
+}
+
+
+static const CGFloat PROGRESS_BAR_HEIGHT = 18.0f;
+static const CGFloat NET_VIEW_HEIGHT = 88.0f;
+
+
+FConsoleWindow::FConsoleWindow()
+: m_window([NSWindow alloc])
+, m_textView([NSTextView alloc])
+, m_scrollView([NSScrollView alloc])
+, m_progressBar(nil)
+, m_netView(nil)
+, m_netMessageText(nil)
+, m_netCountText(nil)
+, m_netProgressBar(nil)
+, m_netAbortButton(nil)
+, m_characterCount(0)
+, m_netCurPos(0)
+, m_netMaxPos(0)
+{
+ const CGFloat initialWidth = 512.0f;
+ const CGFloat initialHeight = 384.0f;
+ const NSRect initialRect = NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight);
+
+ [m_textView initWithFrame:initialRect];
+ [m_textView setEditable:NO];
+ [m_textView setBackgroundColor:RGB(70, 70, 70)];
+ [m_textView setMinSize:NSMakeSize(0.0f, initialHeight)];
+ [m_textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+ [m_textView setVerticallyResizable:YES];
+ [m_textView setHorizontallyResizable:NO];
+ [m_textView setAutoresizingMask:NSViewWidthSizable];
+
+ NSTextContainer* const textContainer = [m_textView textContainer];
+ [textContainer setContainerSize:NSMakeSize(initialWidth, FLT_MAX)];
+ [textContainer setWidthTracksTextView:YES];
+
+ [m_scrollView initWithFrame:NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight)];
+ [m_scrollView setBorderType:NSNoBorder];
+ [m_scrollView setHasVerticalScroller:YES];
+ [m_scrollView setHasHorizontalScroller:NO];
+ [m_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ [m_scrollView setDocumentView:m_textView];
+
+ NSString* const title = [NSString stringWithFormat:@"%s %s - Console", GAMESIG, GetVersionString()];
+
+ [m_window initWithContentRect:initialRect
+ styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ [m_window setMinSize:[m_window frame].size];
+ [m_window setShowsResizeIndicator:NO];
+ [m_window setTitle:title];
+ [m_window center];
+ [m_window exitAppOnClose];
+
+ [[m_window contentView] addSubview:m_scrollView];
+
+ [m_window makeKeyAndOrderFront:nil];
+}
+
+
+static FConsoleWindow* s_instance;
+
+
+void FConsoleWindow::CreateInstance()
+{
+ assert(NULL == s_instance);
+ s_instance = new FConsoleWindow;
+}
+
+void FConsoleWindow::DeleteInstance()
+{
+ assert(NULL != s_instance);
+ delete s_instance;
+ s_instance = NULL;
+}
+
+FConsoleWindow& FConsoleWindow::GetInstance()
+{
+ assert(NULL != s_instance);
+ return *s_instance;
+}
+
+
+void FConsoleWindow::Show(const bool visible)
+{
+ if (visible)
+ {
+ [m_window orderFront:nil];
+ }
+ else
+ {
+ [m_window orderOut:nil];
+ }
+}
+
+void FConsoleWindow::ShowFatalError(const char* const message)
+{
+ SetProgressBar(false);
+ NetDone();
+
+ const CGFloat textViewWidth = [m_scrollView frame].size.width;
+
+ ExpandTextView(-32.0f);
+
+ NSButton* quitButton = [[NSButton alloc] initWithFrame:NSMakeRect(textViewWidth - 76.0f, 0.0f, 72.0f, 30.0f)];
+ [quitButton setAutoresizingMask:NSViewMinXMargin];
+ [quitButton setBezelStyle:NSRoundedBezelStyle];
+ [quitButton setTitle:@"Quit"];
+ [quitButton setKeyEquivalent:@"\r"];
+ [quitButton setTarget:NSApp];
+ [quitButton setAction:@selector(terminate:)];
+
+ NSView* quitPanel = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, textViewWidth, 32.0f)];
+ [quitPanel setAutoresizingMask:NSViewWidthSizable];
+ [quitPanel addSubview:quitButton];
+
+ [[m_window contentView] addSubview:quitPanel];
+ [m_window orderFront:nil];
+
+ AddText(PalEntry(255, 0, 0), "\nExecution could not continue.\n");
+ AddText(PalEntry(255, 255, 170), message);
+ AddText("\n");
+
+ [NSApp runModalForWindow:m_window];
+}
+
+
+void FConsoleWindow::AddText(const char* message)
+{
+ PalEntry color(223, 223, 223);
+
+ char buffer[1024] = {};
+ size_t pos = 0;
+ bool reset = false;
+
+ while (*message != '\0')
+ {
+ if ((TEXTCOLOR_ESCAPE == *message && 0 != pos)
+ || (pos == sizeof buffer - 1)
+ || reset)
+ {
+ buffer[pos] = '\0';
+ pos = 0;
+ reset = false;
+
+ AddText(color, buffer);
+ }
+
+#define CHECK_BUFFER_SPACE \
+ if (pos >= sizeof buffer - 3) { reset = true; continue; }
+
+ if (TEXTCOLOR_ESCAPE == *message)
+ {
+ const BYTE* colorID = reinterpret_cast(message) + 1;
+ if ('\0' == colorID)
+ {
+ break;
+ }
+
+ const EColorRange range = V_ParseFontColor(colorID, CR_UNTRANSLATED, CR_YELLOW);
+
+ if (range != CR_UNDEFINED)
+ {
+ color = V_LogColorFromColorRange(range);
+ }
+
+ message += 2;
+ }
+ else if (0x1d == *message) // Opening bar character
+ {
+ CHECK_BUFFER_SPACE;
+
+ // Insert BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT
+ buffer[pos++] = '\xe2';
+ buffer[pos++] = '\x95';
+ buffer[pos++] = '\xbc';
+ ++message;
+ }
+ else if (0x1e == *message) // Middle bar character
+ {
+ CHECK_BUFFER_SPACE;
+
+ // Insert BOX DRAWINGS HEAVY HORIZONTAL
+ buffer[pos++] = '\xe2';
+ buffer[pos++] = '\x94';
+ buffer[pos++] = '\x81';
+ ++message;
+ }
+ else if (0x1f == *message) // Closing bar character
+ {
+ CHECK_BUFFER_SPACE;
+
+ // Insert BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT
+ buffer[pos++] = '\xe2';
+ buffer[pos++] = '\x95';
+ buffer[pos++] = '\xbe';
+ ++message;
+ }
+ else
+ {
+ buffer[pos++] = *message++;
+ }
+
+#undef CHECK_BUFFER_SPACE
+ }
+
+ if (0 != pos)
+ {
+ buffer[pos] = '\0';
+
+ AddText(color, buffer);
+ }
+
+ if ([m_window isVisible])
+ {
+ [m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)];
+
+ [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
+ }
+}
+
+void FConsoleWindow::AddText(const PalEntry& color, const char* const message)
+{
+ NSString* const text = [NSString stringWithUTF8String:message];
+
+ NSDictionary* const attributes = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSFont systemFontOfSize:14.0f], NSFontAttributeName,
+ RGB(color), NSForegroundColorAttributeName,
+ nil];
+
+ NSAttributedString* const formattedText =
+ [[NSAttributedString alloc] initWithString:text
+ attributes:attributes];
+ [[m_textView textStorage] appendAttributedString:formattedText];
+
+ m_characterCount += [text length];
+}
+
+
+void FConsoleWindow::SetTitleText()
+{
+ static const CGFloat TITLE_TEXT_HEIGHT = 32.0f;
+
+ NSRect textViewFrame = [m_scrollView frame];
+ textViewFrame.size.height -= TITLE_TEXT_HEIGHT;
+ [m_scrollView setFrame:textViewFrame];
+
+ const NSRect titleTextRect = NSMakeRect(
+ 0.0f,
+ textViewFrame.origin.y + textViewFrame.size.height,
+ textViewFrame.size.width,
+ TITLE_TEXT_HEIGHT);
+
+ NSTextField* titleText = [[NSTextField alloc] initWithFrame:titleTextRect];
+ [titleText setStringValue:[NSString stringWithUTF8String:DoomStartupInfo.Name]];
+ [titleText setAlignment:NSCenterTextAlignment];
+ [titleText setTextColor:RGB(DoomStartupInfo.FgColor)];
+ [titleText setBackgroundColor:RGB(DoomStartupInfo.BkColor)];
+ [titleText setFont:[NSFont fontWithName:@"Trebuchet MS Bold" size:18.0f]];
+ [titleText setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
+ [titleText setSelectable:NO];
+ [titleText setBordered:NO];
+
+ [[m_window contentView] addSubview:titleText];
+}
+
+void FConsoleWindow::SetProgressBar(const bool visible)
+{
+ if ( (!visible && nil == m_progressBar)
+ || (visible && nil != m_progressBar))
+ {
+ return;
+ }
+
+ if (visible)
+ {
+ ExpandTextView(-PROGRESS_BAR_HEIGHT);
+
+ m_progressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(2.0f, 0.0f, 508.0f, 16.0f)];
+ [m_progressBar setIndeterminate:NO];
+ [m_progressBar setAutoresizingMask:NSViewWidthSizable];
+
+ [[m_window contentView] addSubview:m_progressBar];
+ }
+ else
+ {
+ ExpandTextView(PROGRESS_BAR_HEIGHT);
+
+ [m_progressBar removeFromSuperview];
+ [m_progressBar release];
+ m_progressBar = nil;
+ }
+}
+
+
+void FConsoleWindow::ExpandTextView(const float height)
+{
+ NSRect textFrame = [m_scrollView frame];
+ textFrame.origin.y -= height;
+ textFrame.size.height += height;
+ [m_scrollView setFrame:textFrame];
+}
+
+
+void FConsoleWindow::Progress(const int current, const int maximum)
+{
+ if (nil == m_progressBar)
+ {
+ return;
+ }
+
+ static unsigned int previousTime = I_MSTime();
+ unsigned int currentTime = I_MSTime();
+
+ if (currentTime - previousTime > 33) // approx. 30 FPS
+ {
+ previousTime = currentTime;
+
+ [m_progressBar setMaxValue:maximum];
+ [m_progressBar setDoubleValue:current];
+
+ [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
+ }
+}
+
+
+void FConsoleWindow::NetInit(const char* const message, const int playerCount)
+{
+ if (nil == m_netView)
+ {
+ SetProgressBar(false);
+ ExpandTextView(-NET_VIEW_HEIGHT);
+
+ // Message like 'Waiting for players' or 'Contacting host'
+ m_netMessageText = [[NSTextField alloc] initWithFrame:NSMakeRect(12.0f, 64.0f, 400.0f, 16.0f)];
+ [m_netMessageText setAutoresizingMask:NSViewWidthSizable];
+ [m_netMessageText setDrawsBackground:NO];
+ [m_netMessageText setSelectable:NO];
+ [m_netMessageText setBordered:NO];
+
+ // Text with connected/total players count
+ m_netCountText = [[NSTextField alloc] initWithFrame:NSMakeRect(428.0f, 64.0f, 72.0f, 16.0f)];
+ [m_netCountText setAutoresizingMask:NSViewMinXMargin];
+ [m_netCountText setAlignment:NSRightTextAlignment];
+ [m_netCountText setDrawsBackground:NO];
+ [m_netCountText setSelectable:NO];
+ [m_netCountText setBordered:NO];
+
+ // Connection progress
+ m_netProgressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(12.0f, 40.0f, 488.0f, 16.0f)];
+ [m_netProgressBar setAutoresizingMask:NSViewWidthSizable];
+ [m_netProgressBar setMaxValue:playerCount];
+
+ if (0 == playerCount)
+ {
+ // Joining game
+ [m_netProgressBar setIndeterminate:YES];
+ [m_netProgressBar startAnimation:nil];
+ }
+ else
+ {
+ // Hosting game
+ [m_netProgressBar setIndeterminate:NO];
+ }
+
+ // Cancel network game button
+ m_netAbortButton = [[NSButton alloc] initWithFrame:NSMakeRect(432.0f, 8.0f, 72.0f, 28.0f)];
+ [m_netAbortButton setAutoresizingMask:NSViewMinXMargin];
+ [m_netAbortButton setBezelStyle:NSRoundedBezelStyle];
+ [m_netAbortButton setTitle:@"Cancel"];
+ [m_netAbortButton setKeyEquivalent:@"\r"];
+ [m_netAbortButton setTarget:NSApp];
+ [m_netAbortButton setAction:@selector(terminate:)];
+
+ // Panel for controls above
+ m_netView = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, 512.0f, NET_VIEW_HEIGHT)];
+ [m_netView setAutoresizingMask:NSViewWidthSizable];
+ [m_netView addSubview:m_netMessageText];
+ [m_netView addSubview:m_netCountText];
+ [m_netView addSubview:m_netProgressBar];
+ [m_netView addSubview:m_netAbortButton];
+
+ NSRect windowRect = [m_window frame];
+ windowRect.origin.y -= NET_VIEW_HEIGHT;
+ windowRect.size.height += NET_VIEW_HEIGHT;
+
+ [m_window setFrame:windowRect display:YES];
+ [[m_window contentView] addSubview:m_netView];
+ }
+
+ [m_netMessageText setStringValue:[NSString stringWithUTF8String:message]];
+
+ m_netCurPos = 0;
+ m_netMaxPos = playerCount;
+
+ NetProgress(1); // You always know about yourself
+}
+
+void FConsoleWindow::NetProgress(const int count)
+{
+ if (0 == count)
+ {
+ ++m_netCurPos;
+ }
+ else
+ {
+ m_netCurPos = count;
+ }
+
+ if (nil == m_netView)
+ {
+ return;
+ }
+
+ if (m_netMaxPos > 1)
+ {
+ [m_netCountText setStringValue:[NSString stringWithFormat:@"%d / %d", m_netCurPos, m_netMaxPos]];
+ [m_netProgressBar setDoubleValue:MIN(m_netCurPos, m_netMaxPos)];
+ }
+}
+
+void FConsoleWindow::NetDone()
+{
+ if (nil != m_netView)
+ {
+ ExpandTextView(NET_VIEW_HEIGHT);
+
+ [m_netView removeFromSuperview];
+ [m_netView release];
+ m_netView = nil;
+
+ // Released by m_netView
+ m_netMessageText = nil;
+ m_netCountText = nil;
+ m_netProgressBar = nil;
+ m_netAbortButton = nil;
+ }
+}
diff --git a/src/posix/cocoa/st_start.mm b/src/posix/cocoa/st_start.mm
new file mode 100644
index 0000000000..36582c64b7
--- /dev/null
+++ b/src/posix/cocoa/st_start.mm
@@ -0,0 +1,192 @@
+/*
+ ** st_start.mm
+ **
+ **---------------------------------------------------------------------------
+ ** Copyright 2015 Alexey Lysiuk
+ ** All rights reserved.
+ **
+ ** Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions
+ ** are met:
+ **
+ ** 1. Redistributions of source code must retain the above copyright
+ ** notice, this list of conditions and the following disclaimer.
+ ** 2. Redistributions in binary form must reproduce the above copyright
+ ** notice, this list of conditions and the following disclaimer in the
+ ** documentation and/or other materials provided with the distribution.
+ ** 3. The name of the author may not be used to endorse or promote products
+ ** derived from this software without specific prior written permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **---------------------------------------------------------------------------
+ **
+ */
+
+#include
+
+#import
+
+#include "c_cvars.h"
+#include "st_console.h"
+#include "st_start.h"
+#include "v_text.h"
+
+
+FStartupScreen *StartScreen;
+
+
+CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
+{
+ if (self < 0)
+ {
+ self = 0;
+ }
+ else if (self > 2)
+ {
+ self = 2;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+
+
+class FBasicStartupScreen : public FStartupScreen
+{
+public:
+ FBasicStartupScreen(int maxProgress, bool showBar);
+ ~FBasicStartupScreen();
+
+ virtual void Progress();
+
+ virtual void NetInit(const char* message, int playerCount);
+ virtual void NetProgress(int count);
+ virtual void NetMessage(const char *format, ...);
+ virtual void NetDone();
+ virtual bool NetLoop(bool (*timerCallback)(void*), void* userData);
+};
+
+
+FBasicStartupScreen::FBasicStartupScreen(int maxProgress, bool showBar)
+: FStartupScreen(maxProgress)
+{
+ FConsoleWindow& consoleWindow = FConsoleWindow::GetInstance();
+ consoleWindow.SetProgressBar(true);
+ consoleWindow.SetTitleText();
+
+#if 0
+ // Testing code, please do not remove
+ consoleWindow.AddText("----------------------------------------------------------------\n");
+ consoleWindow.AddText("1234567890 !@#$%^&*() ,<.>/?;:'\" [{]}\\| `~-_=+ "
+ "This is very very very long message needed to trigger word wrapping...\n\n");
+ consoleWindow.AddText("Multiline...\n\tmessage...\n\t\twith...\n\t\t\ttabs.\n\n");
+
+ consoleWindow.AddText(TEXTCOLOR_BRICK "TEXTCOLOR_BRICK\n" TEXTCOLOR_TAN "TEXTCOLOR_TAN\n");
+ consoleWindow.AddText(TEXTCOLOR_GRAY "TEXTCOLOR_GRAY & TEXTCOLOR_GREY\n");
+ consoleWindow.AddText(TEXTCOLOR_GREEN "TEXTCOLOR_GREEN\n" TEXTCOLOR_BROWN "TEXTCOLOR_BROWN\n");
+ consoleWindow.AddText(TEXTCOLOR_GOLD "TEXTCOLOR_GOLD\n" TEXTCOLOR_RED "TEXTCOLOR_RED\n");
+ consoleWindow.AddText(TEXTCOLOR_BLUE "TEXTCOLOR_BLUE\n" TEXTCOLOR_ORANGE "TEXTCOLOR_ORANGE\n");
+ consoleWindow.AddText(TEXTCOLOR_WHITE "TEXTCOLOR_WHITE\n" TEXTCOLOR_YELLOW "TEXTCOLOR_YELLOW\n");
+ consoleWindow.AddText(TEXTCOLOR_UNTRANSLATED "TEXTCOLOR_UNTRANSLATED\n");
+ consoleWindow.AddText(TEXTCOLOR_BLACK "TEXTCOLOR_BLACK\n" TEXTCOLOR_LIGHTBLUE "TEXTCOLOR_LIGHTBLUE\n");
+ consoleWindow.AddText(TEXTCOLOR_CREAM "TEXTCOLOR_CREAM\n" TEXTCOLOR_OLIVE "TEXTCOLOR_OLIVE\n");
+ consoleWindow.AddText(TEXTCOLOR_DARKGREEN "TEXTCOLOR_DARKGREEN\n" TEXTCOLOR_DARKRED "TEXTCOLOR_DARKRED\n");
+ consoleWindow.AddText(TEXTCOLOR_DARKBROWN "TEXTCOLOR_DARKBROWN\n" TEXTCOLOR_PURPLE "TEXTCOLOR_PURPLE\n");
+ consoleWindow.AddText(TEXTCOLOR_DARKGRAY "TEXTCOLOR_DARKGRAY\n" TEXTCOLOR_CYAN "TEXTCOLOR_CYAN\n");
+ consoleWindow.AddText(TEXTCOLOR_NORMAL "TEXTCOLOR_NORMAL\n" TEXTCOLOR_BOLD "TEXTCOLOR_BOLD\n");
+ consoleWindow.AddText(TEXTCOLOR_CHAT "TEXTCOLOR_CHAT\n" TEXTCOLOR_TEAMCHAT "TEXTCOLOR_TEAMCHAT\n");
+ consoleWindow.AddText("----------------------------------------------------------------\n");
+#endif // _DEBUG
+}
+
+FBasicStartupScreen::~FBasicStartupScreen()
+{
+ FConsoleWindow::GetInstance().SetProgressBar(false);
+}
+
+
+void FBasicStartupScreen::Progress()
+{
+ if (CurPos < MaxPos)
+ {
+ ++CurPos;
+ }
+
+ FConsoleWindow::GetInstance().Progress(CurPos, MaxPos);
+}
+
+
+void FBasicStartupScreen::NetInit(const char* const message, const int playerCount)
+{
+ FConsoleWindow::GetInstance().NetInit(message, playerCount);
+}
+
+void FBasicStartupScreen::NetProgress(const int count)
+{
+ FConsoleWindow::GetInstance().NetProgress(count);
+}
+
+void FBasicStartupScreen::NetMessage(const char* const format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ FString message;
+ message.VFormat(format, args);
+ va_end(args);
+
+ Printf("%s\n", message.GetChars());
+}
+
+void FBasicStartupScreen::NetDone()
+{
+ FConsoleWindow::GetInstance().NetDone();
+}
+
+bool FBasicStartupScreen::NetLoop(bool (*timerCallback)(void*), void* const userData)
+{
+ while (true)
+ {
+ if (timerCallback(userData))
+ {
+ break;
+ }
+
+ [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
+
+ // Do not poll to often
+ usleep(50000);
+ }
+
+ return true;
+}
+
+
+// ---------------------------------------------------------------------------
+
+
+FStartupScreen *FStartupScreen::CreateInstance(const int maxProgress)
+{
+ return new FBasicStartupScreen(maxProgress, true);
+}
+
+
+// ---------------------------------------------------------------------------
+
+
+void ST_Endoom()
+{
+ extern void I_ShutdownJoysticks();
+ I_ShutdownJoysticks();
+
+ exit(0);
+}
diff --git a/src/posix/osx/iwadpicker_cocoa.mm b/src/posix/osx/iwadpicker_cocoa.mm
index d2bc1ff0cc..5f2ff2ae2a 100644
--- a/src/posix/osx/iwadpicker_cocoa.mm
+++ b/src/posix/osx/iwadpicker_cocoa.mm
@@ -462,20 +462,14 @@ static void RestartWithParameters(const char* iwadPath, NSString* parameters)
[pool release];
}
-void I_SetMainWindowVisible(bool visible);
-
// Simple wrapper so we can call this from outside.
int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
- I_SetMainWindowVisible(false);
-
IWADPicker *picker = [IWADPicker alloc];
int ret = [picker pickIWad:wads num:numwads showWindow:showwin defaultWad:defaultiwad];
- I_SetMainWindowVisible(true);
-
NSString* parametersToAppend = [picker commandLineParameters];
osx_additional_parameters = [parametersToAppend UTF8String];
diff --git a/src/posix/sdl/crashcatcher.c b/src/posix/sdl/crashcatcher.c
index f85713e312..70c9e7b0cb 100644
--- a/src/posix/sdl/crashcatcher.c
+++ b/src/posix/sdl/crashcatcher.c
@@ -15,7 +15,7 @@
#ifndef PR_SET_PTRACER
#define PR_SET_PTRACER 0x59616d61
#endif
-#elif defined (__APPLE__)
+#elif defined (__APPLE__) || defined (__FreeBSD__)
#include
#endif
diff --git a/src/posix/sdl/i_gui.cpp b/src/posix/sdl/i_gui.cpp
index f9e6714b47..37a3b1062f 100644
--- a/src/posix/sdl/i_gui.cpp
+++ b/src/posix/sdl/i_gui.cpp
@@ -54,8 +54,3 @@ bool I_SetCursor(FTexture *cursorpic)
}
return true;
}
-
-void I_SetMainWindowVisible(bool visible)
-{
-
-}
diff --git a/src/posix/i_system.cpp b/src/posix/sdl/i_system.cpp
similarity index 100%
rename from src/posix/i_system.cpp
rename to src/posix/sdl/i_system.cpp
diff --git a/src/posix/st_start.cpp b/src/posix/sdl/st_start.cpp
similarity index 100%
rename from src/posix/st_start.cpp
rename to src/posix/sdl/st_start.cpp
diff --git a/src/r_defs.h b/src/r_defs.h
index b741b5f6bb..6f69a26a01 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -248,6 +248,11 @@ struct secplane_t
return FixedMul (ic, -d - DMulScale16 (a, v->x, b, v->y));
}
+ fixed_t ZatPoint (const AActor *ac) const
+ {
+ return FixedMul (ic, -d - DMulScale16 (a, ac->X(), b, ac->Y()));
+ }
+
// Returns the value of z at (x,y) if d is equal to dist
fixed_t ZatPointDist (fixed_t x, fixed_t y, fixed_t dist) const
{
@@ -346,7 +351,7 @@ enum
SECF_DRAWN = 128, // sector has been drawn at least once
SECF_HIDDEN = 256, // Do not draw on textured automap
SECF_NOFLOORSKYBOX = 512, // force use of regular sky
- SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky
+ SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky (do not separate from NOFLOORSKYBOX!!!)
};
enum
@@ -355,6 +360,20 @@ enum
SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector
SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast.
SECF_NORESPAWN = 8, // players can not respawn in this sector
+ SECF_FRICTION = 16, // sector has friction enabled
+ SECF_PUSH = 32, // pushers enabled
+ SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.)
+ SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage
+ SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode
+ SECF_ENDLEVEL = 512, // ends level when health goes below 10
+ SECF_HAZARD = 1024, // Change to Strife's delayed damage handling.
+
+ SECF_WASSECRET = 1 << 30, // a secret that was discovered
+ SECF_SECRET = 1 << 31, // a secret sector
+
+ SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD,
+ SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags
+ SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers
};
enum
@@ -427,6 +446,23 @@ struct FTransform
fixed_t base_angle, base_yoffs;
};
+struct secspecial_t
+{
+ FNameNoInit damagetype; // [RH] Means-of-death for applied damage
+ int damageamount; // [RH] Damage to do while standing on floor
+ short special;
+ short damageinterval; // Interval for damage application
+ short leakydamage; // chance of leaking through radiation suit
+ int Flags;
+
+ void Clear()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+FArchive &operator<< (FArchive &arc, secspecial_t &p);
+
struct sector_t
{
// Member functions
@@ -642,7 +678,37 @@ struct sector_t
return pos == floor? floorplane:ceilingplane;
}
+ bool isSecret() const
+ {
+ return !!(Flags & SECF_SECRET);
+ }
+ bool wasSecret() const
+ {
+ return !!(Flags & SECF_WASSECRET);
+ }
+
+ void ClearSecret()
+ {
+ Flags &= ~SECF_SECRET;
+ }
+
+ void ClearSpecial()
+ {
+ // clears all variables that originate from 'special'. Used for sector type transferring thinkers
+ special = 0;
+ damageamount = 0;
+ damageinterval = 0;
+ damagetype = NAME_None;
+ leakydamage = 0;
+ Flags &= ~SECF_SPECIALFLAGS;
+ }
+
+ int GetTerrain(int pos) const;
+
+ void TransferSpecial(sector_t *model);
+ void GetSpecial(secspecial_t *spec);
+ void SetSpecial(const secspecial_t *spec);
bool PlaneMoving(int pos);
@@ -675,6 +741,8 @@ struct sector_t
// when processed as mobj properties. Fix is to make them sector properties.
fixed_t friction, movefactor;
+ int terrainnum[2];
+
// thinker_t for reversable actions
TObjPtr floordata; // jff 2/22/98 make thinkers on
TObjPtr ceilingdata; // floors, ceilings, lighting,
@@ -709,9 +777,11 @@ struct sector_t
// thinglist is a subset of touching_thinglist
struct msecnode_t *touching_thinglist; // phares 3/14/98
- float gravity; // [RH] Sector gravity (1.0 is normal)
- short damage; // [RH] Damage to do while standing on floor
- short mod; // [RH] Means-of-death for applied damage
+ float gravity; // [RH] Sector gravity (1.0 is normal)
+ FNameNoInit damagetype; // [RH] Means-of-death for applied damage
+ int damageamount; // [RH] Damage to do while standing on floor
+ short damageinterval; // Interval for damage application
+ short leakydamage; // chance of leaking through radiation suit
WORD ZoneNumber; // [RH] Zone this sector belongs to
WORD MoreFlags; // [RH] Internal sector flags
@@ -725,9 +795,8 @@ struct sector_t
// [RH] The sky box to render for this sector. NULL means use a
// regular sky.
- TObjPtr FloorSkyBox, CeilingSkyBox;
+ TObjPtr SkyBoxes[2];
- short secretsector; //jff 2/16/98 remembers if sector WAS secret (automap)
int sectornum; // for comparing sector copies
extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat.
diff --git a/src/r_plane.cpp b/src/r_plane.cpp
index 8cab342302..96a77930a6 100644
--- a/src/r_plane.cpp
+++ b/src/r_plane.cpp
@@ -1280,6 +1280,7 @@ void R_DrawSkyBoxes ()
ds_p->sprtopclip = R_NewOpening (pl->maxx - pl->minx + 1);
ds_p->maskedtexturecol = ds_p->swall = -1;
ds_p->bFogBoundary = false;
+ ds_p->fake = 0;
memcpy (openings + ds_p->sprbottomclip, floorclip + pl->minx, (pl->maxx - pl->minx + 1)*sizeof(short));
memcpy (openings + ds_p->sprtopclip, ceilingclip + pl->minx, (pl->maxx - pl->minx + 1)*sizeof(short));
diff --git a/src/resourcefiles/file_7z.cpp b/src/resourcefiles/file_7z.cpp
index 1fb553932d..65676fcf4f 100644
--- a/src/resourcefiles/file_7z.cpp
+++ b/src/resourcefiles/file_7z.cpp
@@ -252,25 +252,26 @@ bool F7ZFile::Open(bool quiet)
}
return false;
}
- NumLumps = Archive->DB.db.NumFiles;
+ CSzArEx* const archPtr = &Archive->DB;
+
+ NumLumps = archPtr->NumFiles;
Lumps = new F7ZLump[NumLumps];
F7ZLump *lump_p = Lumps;
TArray nameUTF16;
TArray nameASCII;
+
for (DWORD i = 0; i < NumLumps; ++i)
{
- CSzFileItem *file = &Archive->DB.db.Files[i];
-
// skip Directories
- if (file->IsDir)
+ if (SzArEx_IsDir(archPtr, i))
{
skipped++;
continue;
}
- const size_t nameLength = SzArEx_GetFileNameUtf16(&Archive->DB, i, NULL);
+ const size_t nameLength = SzArEx_GetFileNameUtf16(archPtr, i, NULL);
if (0 == nameLength)
{
@@ -280,7 +281,7 @@ bool F7ZFile::Open(bool quiet)
nameUTF16.Resize((unsigned)nameLength);
nameASCII.Resize((unsigned)nameLength);
- SzArEx_GetFileNameUtf16(&Archive->DB, i, &nameUTF16[0]);
+ SzArEx_GetFileNameUtf16(archPtr, i, &nameUTF16[0]);
for (size_t c = 0; c < nameLength; ++c)
{
nameASCII[c] = static_cast(nameUTF16[c]);
@@ -291,7 +292,7 @@ bool F7ZFile::Open(bool quiet)
name.ToLower();
lump_p->LumpNameSetup(name);
- lump_p->LumpSize = int(file->Size);
+ lump_p->LumpSize = static_cast(SzArEx_GetFileSize(archPtr, i));
lump_p->Owner = this;
lump_p->Flags = LUMPF_ZIPFILE;
lump_p->Position = i;
diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp
index 4042ca421a..e7a617f5a7 100644
--- a/src/sound/fmodsound.cpp
+++ b/src/sound/fmodsound.cpp
@@ -462,14 +462,12 @@ public:
Stream->release();
Channel = NULL;
Stream = NULL;
- Owner->Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES);
// Open the stream asynchronously, so we don't hang the game while trying to reconnect.
// (It would be nice to do the initial open asynchronously as well, but I'd need to rethink
// the music system design to pull that off.)
result = Owner->Sys->createSound(URL, (Loop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF) | FMOD_SOFTWARE | FMOD_2D |
FMOD_CREATESTREAM | FMOD_NONBLOCKING, NULL, &Stream);
JustStarted = true;
- Owner->Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES);
return result != FMOD_OK;
}
if (JustStarted && openstate == FMOD_OPENSTATE_PLAYING)
@@ -1170,6 +1168,9 @@ bool FMODSoundRenderer::Init()
}
Sys->set3DSettings(0.5f, 96.f, 1.f);
Sys->set3DRolloffCallback(RolloffCallback);
+ // The default is 16k, which periodically starves later FMOD versions
+ // when streaming FLAC files.
+ Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES);
snd_sfxvolume.Callback ();
return true;
}
@@ -1733,10 +1734,6 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *url, int flags)
exinfo.dlsname = patches;
}
- // Use a larger buffer for URLs so that it's less likely to be effected
- // by hiccups in the data rate from the remote server.
- Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES);
-
result = Sys->createSound(url, mode, &exinfo, &stream);
if(result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL)
{
@@ -1748,9 +1745,6 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *url, int flags)
}
}
- // Restore standard buffer size.
- Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES);
-
if(result != FMOD_OK)
return NULL;
diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp
index 9f50b41555..667de88421 100644
--- a/src/sound/music_midi_timidity.cpp
+++ b/src/sound/music_midi_timidity.cpp
@@ -58,7 +58,7 @@ CUSTOM_CVAR (Int, timidity_pipe, 90, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
}
}
-CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
+CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{ // Clamp frequency to Timidity's limits
if (self < 4000)
self = 4000;
diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 9f27dc0e58..dd5f4e7a1f 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -796,7 +796,7 @@ static int DoJumpIfCloser(AActor *target, VM_ARGS)
// No target - no jump
if (!target)
return numret;
- if (P_AproxDistance(self->x-target->x, self->y-target->y) < dist &&
+ if (self->AproxDistance(target) < dist &&
(noz ||
((self->z > target->z && self->z - (target->z + target->height) < dist) ||
(self->z <= target->z && target->z - (self->z + self->height) < dist))))
@@ -1658,7 +1658,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
if (!(flags & CPF_NOTURN))
{
// turn to face target
- self->angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y);
+ self->angle = self->AngleTo(linetarget);
}
if (flags & CPF_PULLIN) self->flags |= MF_JUSTATTACKED;
@@ -1786,10 +1786,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
if (aim)
{
- self->angle = R_PointToAngle2 (self->x,
- self->y,
- self->target->x,
- self->target->y);
+ self->angle = self->AngleTo(self->target);
}
self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, aim ? self->target : NULL);
if (linetarget == NULL && aim)
@@ -1803,9 +1800,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
// Let the aim trail behind the player
if (aim)
{
- saved_angle = self->angle = R_PointToAngle2 (self->x, self->y,
- self->target->x - self->target->velx * 3,
- self->target->y - self->target->vely * 3);
+ saved_angle = self->angle = self->AngleTo(self->target, -self->target->velx * 3, -self->target->vely * 3);
if (aim == CRF_AIMDIRECT)
{
@@ -1814,9 +1809,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
self->x += spawnofs_xy * finecosine[self->angle];
self->y += spawnofs_xy * finesine[self->angle];
spawnofs_xy = 0;
- self->angle = R_PointToAngle2 (self->x, self->y,
- self->target->x - self->target->velx * 3,
- self->target->y - self->target->vely * 3);
+ self->angle = self->AngleTo(self->target,- self->target->velx * 3, -self->target->vely * 3);
}
if (self->target->flags & MF_SHADOW)
@@ -2718,7 +2711,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn)
}
if (flags & FTF_REMOVE)
{
- self->Destroy();
+ P_RemoveThing(self);
}
}
return 0;
@@ -2751,7 +2744,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut)
}
if (flags & FTF_REMOVE)
{
- self->Destroy();
+ P_RemoveThing(self);
}
}
return 0;
@@ -2798,7 +2791,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo)
}
if (self->alpha == target && (flags & FTF_REMOVE))
{
- self->Destroy();
+ P_RemoveThing(self);
}
return 0;
}
@@ -3329,18 +3322,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn)
if (flags & RSF_TELEFRAG)
{
// [KS] DIE DIE DIE DIE erm *ahem* =)
- oktorespawn = P_TeleportMove(self, self->x, self->y, self->z, true);
- if (oktorespawn)
- { // Need to do this over again, since P_TeleportMove() will redo
- // it with the proper point-on-side calculation.
- self->UnlinkFromWorld();
- self->LinkToWorld(true);
- sector_t *sec = self->Sector;
- self->dropoffz =
- self->floorz = sec->floorplane.ZatPoint(self->x, self->y);
- self->ceilingz = sec->ceilingplane.ZatPoint(self->x, self->y);
- P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS);
- }
+ oktorespawn = P_TeleportMove(self, self->x, self->y, self->z, true, false);
}
else
{
@@ -3644,8 +3626,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF)
if (target)
{
- FVector2 xyvec(target->x - x1, target->y - y1);
- fixed_t distance = P_AproxDistance((fixed_t)xyvec.Length(), target->z - z1);
+ fixed_t xydist = self->Distance2D(target);
+ fixed_t distance = P_AproxDistance(xydist, target->z - z1);
if (range && !(flags & CLOFF_CHECKPARTIAL))
{
@@ -3660,7 +3642,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF)
{
ang = self->angle;
}
- else ang = R_PointToAngle2 (x1, y1, target->x, target->y);
+ else ang = self->AngleTo (target);
angle += ang;
@@ -3675,11 +3657,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF)
}
else if (flags & CLOFF_AIM_VERT_NOOFFSET)
{
- pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + offsetheight + target->height / 2);
+ pitch += R_PointToAngle2 (0,0, xydist, target->z - z1 + offsetheight + target->height / 2);
}
else
{
- pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + target->height / 2);
+ pitch += R_PointToAngle2 (0,0, xydist, target->z - z1 + target->height / 2);
}
}
else if (flags & CLOFF_ALLOWNULL)
@@ -3858,8 +3840,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
if ((flags & JLOSF_ALLYNOJUMP) && self->IsFriend(target))
return numret;
- fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y);
- distance = P_AproxDistance(distance, target->z - self->z);
+ fixed_t distance = self->AproxDistance3D(target);
if (dist_max && (distance > dist_max))
return numret;
@@ -3890,11 +3871,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
if (fov && (fov < ANGLE_MAX))
{
- an = R_PointToAngle2 (viewport->x,
- viewport->y,
- target->x,
- target->y)
- - viewport->angle;
+ an = viewport->AngleTo(target) - viewport->angle;
if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2)))
{
@@ -3955,8 +3932,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS)
return numret;
}
- fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y);
- distance = P_AproxDistance(distance, target->z - self->z);
+ fixed_t distance = self->AproxDistance3D(target);
if (dist_max && (distance > dist_max))
{
@@ -3979,11 +3955,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS)
if (fov && (fov < ANGLE_MAX))
{
- an = R_PointToAngle2 (target->x,
- target->y,
- self->x,
- self->y)
- - target->angle;
+ an = target->AngleTo(self) - target->angle;
if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2)))
{
@@ -4947,7 +4919,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack)
A_FaceTarget (self);
// Target can dodge if it can see enemy
- angle_t angle = R_PointToAngle2(self->target->x, self->target->y, self->x, self->y) - self->target->angle;
+ angle_t angle = self->target->AngleTo(self) - self->target->angle;
angle >>= 24;
bool dodge = (P_CheckSight(self->target, self) && (angle>226 || angle<30));
@@ -4986,7 +4958,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack)
dx = self->target->x;
dy = self->target->y;
dz = self->target->z + (self->target->height>>1);
- angle = R_PointToAngle2(dx, dy, self->x, self->y);
+ angle = self->target->AngleTo(self);
dx += FixedMul(self->target->radius, finecosine[angle>>ANGLETOFINESHIFT]);
dy += FixedMul(self->target->radius, finesine[angle>>ANGLETOFINESHIFT]);
@@ -5021,7 +4993,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack)
if (spawnblood)
{
P_SpawnBlood(dx, dy, dz, angle, newdam > 0 ? newdam : damage, self->target);
- P_TraceBleed(newdam > 0 ? newdam : damage, self->target, R_PointToAngle2(self->x, self->y, dx, dy), 0);
+ P_TraceBleed(newdam > 0 ? newdam : damage, self->target, self->AngleTo(dx, dy, self->target), 0);
}
}
}
@@ -6320,7 +6292,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity)
continue;
//Make sure it's in range and respect the desire for Z or not.
- if (P_AproxDistance(ref->x - mo->x, ref->y - mo->y) < distance &&
+ if (ref->AproxDistance(mo) < distance &&
((flags & CPXF_NOZ) ||
((ref->z > mo->z && ref->z - (mo->z + mo->height) < distance) ||
(ref->z <= mo->z && mo->z - (ref->z + ref->height) < distance))))
diff --git a/src/timidity/instrum_dls.cpp b/src/timidity/instrum_dls.cpp
index 286fcb1a35..02b8e59c0e 100644
--- a/src/timidity/instrum_dls.cpp
+++ b/src/timidity/instrum_dls.cpp
@@ -1126,7 +1126,7 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
sample->key_group = (SBYTE)rgn->header->usKeyGroup;
sample->low_freq = note_to_freq(rgn->header->RangeKey.usLow);
sample->high_freq = note_to_freq(rgn->header->RangeKey.usHigh);
- sample->root_freq = note_to_freq(rgn->wsmp->usUnityNote);
+ sample->root_freq = note_to_freq(rgn->wsmp->usUnityNote + rgn->wsmp->sFineTune * .01f);
sample->low_vel = (BYTE)rgn->header->RangeVelocity.usLow;
sample->high_vel = (BYTE)rgn->header->RangeVelocity.usHigh;
@@ -1137,15 +1137,17 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
convert_sample_data(sample, wave->data);
if (rgn->wsmp->cSampleLoops)
{
- sample->modes |= (PATCH_LOOPEN | PATCH_SUSTAIN);
+ sample->modes |= (PATCH_LOOPEN | PATCH_SUSTAIN/* | PATCH_NO_SRELEASE*/);
sample->loop_start = rgn->wsmp_loop->ulStart / 2;
sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2);
}
+ sample->scale_factor = 1024;
+ sample->scale_note = rgn->wsmp->usUnityNote;
if (sample->modes & PATCH_SUSTAIN)
{
int value;
- double attack, hold, decay, release; int sustain;
+ int attack, hold, decay, release; int sustain;
CONNECTIONLIST *art = NULL;
CONNECTION *artList = NULL;
@@ -1157,16 +1159,11 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
artList = rgn->artList;
}
- value = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME);
- attack = to_msec(value);
- value = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME);
- hold = to_msec(value);
- value = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME);
- decay = to_msec(value);
- value = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME);
- release = to_msec(value);
- value = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL);
- sustain = (int)((1.0 - to_normalized_percent(value)) * 250.0);
+ attack = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME);
+ hold = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME);
+ decay = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME);
+ release = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME);
+ sustain = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL);
value = load_connection(art->cConnections, artList, CONN_DST_PAN);
sample->panning = (int)((0.5 + to_normalized_percent(value)) * 16383.f);
@@ -1174,12 +1171,12 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release);
*/
- sample->envelope.sf2.decay_vol = 0;
- sample->envelope.sf2.attack_vol = (short)attack;
- sample->envelope.sf2.hold_vol = (short)hold;
- sample->envelope.sf2.decay_vol = (short)decay;
- sample->envelope.sf2.release_vol = (short)release;
- sample->envelope.sf2.sustain_vol = (short)sustain;
+ sample->envelope.sf2.delay_vol = -32768;
+ sample->envelope.sf2.attack_vol = (short)(attack >> 16);
+ sample->envelope.sf2.hold_vol = (short)(hold >> 16);
+ sample->envelope.sf2.decay_vol = (short)(decay >> 16);
+ sample->envelope.sf2.release_vol = (short)(release >> 16);
+ sample->envelope.sf2.sustain_vol = (short)(sustain >> 16);
}
sample->data_length <<= FRACTION_BITS;
diff --git a/src/timidity/mix.cpp b/src/timidity/mix.cpp
index f977103266..beda91e16c 100644
--- a/src/timidity/mix.cpp
+++ b/src/timidity/mix.cpp
@@ -231,6 +231,10 @@ bool SF2Envelope::Update(Voice *v)
double sec;
double newvolume = 0;
+ // NOTE! The volume scale is different for different stages of the
+ // envelope generator:
+ // Attack stage goes from 0.0 -> 1.0, multiplied directly to the output.
+ // The following stages go from 0 -> -1000 cB (but recorded positively)
switch (stage)
{
case SF2_DELAY:
@@ -333,6 +337,11 @@ bool SF2Envelope::Update(Voice *v)
#define FLUID_ATTEN_POWER_FACTOR (-531.509)
#define atten2amp(x) pow(10.0, (x) / FLUID_ATTEN_POWER_FACTOR)
+static double cb_to_amp(double x) // centibels to amp
+{
+ return pow(10, x / -200.f);
+}
+
void SF2Envelope::ApplyToAmp(Voice *v)
{
double amp;
@@ -343,13 +352,21 @@ void SF2Envelope::ApplyToAmp(Voice *v)
v->right_mix = 0;
return;
}
- else if (stage == SF2_ATTACK)
+
+ amp = v->sample->type == INST_SF2 ? atten2amp(v->attenuation) : cb_to_amp(v->attenuation);
+
+ switch (stage)
{
- amp = atten2amp(v->attenuation) * volume;
- }
- else
- {
- amp = atten2amp(v->attenuation) * cb_to_amp(volume);
+ case SF2_ATTACK:
+ amp *= volume;
+ break;
+
+ case SF2_HOLD:
+ break;
+
+ default:
+ amp *= cb_to_amp(volume);
+ break;
}
amp *= FINAL_MIX_SCALE * 0.5;
v->left_mix = float(amp * v->left_offset);
diff --git a/src/timidity/timidity.cpp b/src/timidity/timidity.cpp
index 807bc07b73..267edbb7e2 100644
--- a/src/timidity/timidity.cpp
+++ b/src/timidity/timidity.cpp
@@ -678,6 +678,9 @@ int LoadDMXGUS()
return 0;
}
+DLS_Data *LoadDLS(FILE *src);
+void FreeDLS(DLS_Data *data);
+
Renderer::Renderer(float sample_rate, const char *args)
{
// 'args' should be used to load a custom config or DMXGUS, but since setup currently requires a snd_reset call, this will need some refactoring first
@@ -698,9 +701,14 @@ Renderer::Renderer(float sample_rate, const char *args)
if (def_instr_name.IsNotEmpty())
set_default_instrument(def_instr_name);
- voices = clamp(midi_voices, 16, 256);
+ voices = MAX(*midi_voices, 16);
voice = new Voice[voices];
drumchannels = DEFAULT_DRUMCHANNELS;
+#if 0
+ FILE *f = fopen("c:\\windows\\system32\\drivers\\gm.dls", "rb");
+ patches = LoadDLS(f);
+ fclose(f);
+#endif
}
Renderer::~Renderer()
@@ -713,6 +721,10 @@ Renderer::~Renderer()
{
delete[] voice;
}
+ if (patches != NULL)
+ {
+ FreeDLS(patches);
+ }
}
void Renderer::ComputeOutput(float *buffer, int count)
diff --git a/src/timidity/timidity.h b/src/timidity/timidity.h
index 45e23a9f9c..ac423c1e2a 100644
--- a/src/timidity/timidity.h
+++ b/src/timidity/timidity.h
@@ -445,7 +445,7 @@ struct Channel
struct MinEnvelope
{
- int stage;
+ BYTE stage;
BYTE bUpdating;
};
@@ -599,7 +599,6 @@ const double log_of_2 = 0.69314718055994529;
#define freq_to_note(x) (log((x) / 8175.7989473096690661233836992789) * (12.0 / log_of_2))
#define calc_gf1_amp(x) (pow(2.0,((x)*16.0 - 16.0))) // Actual GUS equation
-#define cb_to_amp(x) (pow(10.0, (x) * (1 / -200.0))) // centibels to amp
/*
timidity.h
diff --git a/src/version.h b/src/version.h
index 682c5165ee..b8c4facb0d 100644
--- a/src/version.h
+++ b/src/version.h
@@ -76,7 +76,7 @@ const char *GetVersionString();
// Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got.
-#define SAVEVER 4527
+#define SAVEVER 4531
#define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
diff --git a/src/w_wad.cpp b/src/w_wad.cpp
index 552228557c..42e5c17b9f 100644
--- a/src/w_wad.cpp
+++ b/src/w_wad.cpp
@@ -961,8 +961,10 @@ void FWadCollection::RenameNerve ()
//
// FixMacHexen
//
-// Rename unused high resolution font lumps because they are incorrectly
-// treated as extended characters
+// Discard all extra lumps in Mac version of Hexen IWAD (demo or full)
+// to avoid any issues caused by names of these lumps, including:
+// * Wrong height of small font
+// * Broken life bar of mage class
//
//==========================================================================
@@ -973,22 +975,51 @@ void FWadCollection::FixMacHexen()
return;
}
- for (int i = GetFirstLump(IWAD_FILENUM), last = GetLastLump(IWAD_FILENUM); i <= last; ++i)
+ FileReader* const reader = GetFileReader(IWAD_FILENUM);
+ const long iwadSize = reader->GetLength();
+
+ static const long DEMO_SIZE = 13596228;
+ static const long FULL_SIZE = 21078584;
+
+ if ( DEMO_SIZE != iwadSize
+ && FULL_SIZE != iwadSize)
{
- assert(IWAD_FILENUM == LumpInfo[i].wadnum);
+ return;
+ }
- FResourceLump* const lump = LumpInfo[i].lump;
- char* const name = lump->Name;
+ reader->Seek(0, SEEK_SET);
- // Unwanted lumps are named like FONTA??1
+ BYTE checksum[16];
+ MD5Context md5;
+ md5.Update(reader, iwadSize);
+ md5.Final(checksum);
- if (8 == strlen(name)
- && MAKE_ID('F', 'O', 'N', 'T') == lump->dwName
- && 'A' == name[4] && '1' == name[7]
- && isdigit(name[5]) && isdigit(name[6]))
- {
- name[0] = '\0';
- }
+ static const BYTE HEXEN_DEMO_MD5[16] =
+ {
+ 0x92, 0x5f, 0x9f, 0x50, 0x00, 0xe1, 0x7d, 0xc8,
+ 0x4b, 0x0a, 0x6a, 0x3b, 0xed, 0x3a, 0x6f, 0x31
+ };
+
+ static const BYTE HEXEN_FULL_MD5[16] =
+ {
+ 0xb6, 0x81, 0x40, 0xa7, 0x96, 0xf6, 0xfd, 0x7f,
+ 0x3a, 0x5d, 0x32, 0x26, 0xa3, 0x2b, 0x93, 0xbe
+ };
+
+ if ( 0 != memcmp(HEXEN_DEMO_MD5, checksum, sizeof checksum)
+ && 0 != memcmp(HEXEN_FULL_MD5, checksum, sizeof checksum))
+ {
+ return;
+ }
+
+ static const int EXTRA_LUMPS = 299;
+
+ const int lastLump = GetLastLump(IWAD_FILENUM);
+ assert(GetFirstLump(IWAD_FILENUM) + 299 < lastLump);
+
+ for (int i = lastLump - EXTRA_LUMPS + 1; i <= lastLump; ++i)
+ {
+ LumpInfo[i].lump->Name[0] = '\0';
}
}
diff --git a/src/wildmidi/common.h b/src/wildmidi/common.h
index 44e90efdd4..a089329e0c 100644
--- a/src/wildmidi/common.h
+++ b/src/wildmidi/common.h
@@ -27,14 +27,14 @@
#ifndef __COMMON_H
#define __COMMON_H
-#define SAMPLE_16BIT 0x01
-#define SAMPLE_UNSIGNED 0x02
-#define SAMPLE_LOOP 0x04
-#define SAMPLE_PINGPONG 0x08
-#define SAMPLE_REVERSE 0x10
-#define SAMPLE_SUSTAIN 0x20
-#define SAMPLE_ENVELOPE 0x40
-#define SAMPLE_CLAMPED 0x80
+#define SAMPLE_16BIT 0x01
+#define SAMPLE_UNSIGNED 0x02
+#define SAMPLE_LOOP 0x04
+#define SAMPLE_PINGPONG 0x08
+#define SAMPLE_REVERSE 0x10
+#define SAMPLE_SUSTAIN 0x20
+#define SAMPLE_ENVELOPE 0x40
+#define SAMPLE_CLAMPED 0x80
#ifdef DEBUG_SAMPLES
#define SAMPLE_CONVERT_DEBUG(dx) printf("\r%s\n",dx)
@@ -45,19 +45,19 @@
extern unsigned short int _WM_SampleRate;
struct _sample {
- unsigned long int data_length;
- unsigned long int loop_start;
- unsigned long int loop_end;
- unsigned long int loop_size;
+ unsigned int data_length;
+ unsigned int loop_start;
+ unsigned int loop_end;
+ unsigned int loop_size;
unsigned char loop_fraction;
- unsigned short int rate;
- unsigned long int freq_low;
- unsigned long int freq_high;
- unsigned long int freq_root;
+ unsigned short rate;
+ unsigned int freq_low;
+ unsigned int freq_high;
+ unsigned int freq_root;
unsigned char modes;
- signed long int env_rate[7];
- signed long int env_target[7];
- unsigned long int inc_div;
+ signed int env_rate[7];
+ signed int env_target[7];
+ unsigned int inc_div;
signed short *data;
struct _sample *next;
};
diff --git a/src/wildmidi/gus_pat.cpp b/src/wildmidi/gus_pat.cpp
index be3422db55..8f4824dc53 100644
--- a/src/wildmidi/gus_pat.cpp
+++ b/src/wildmidi/gus_pat.cpp
@@ -1,31 +1,26 @@
/*
- gus_pat.c
-
- Midi Wavetable Processing library
-
- Copyright (C) Chris Ison 2001-2011
- Copyright (C) Bret Curtis 2013-2014
-
- This file is part of WildMIDI.
-
- WildMIDI is free software: you can redistribute and/or modify the player
- under the terms of the GNU General Public License and you can redistribute
- and/or modify the library under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation, either version 3 of
- the licenses, or(at your option) any later version.
-
- WildMIDI 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 and
- the GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU General Public License and the
- GNU Lesser General Public License along with WildMIDI. If not, see
- .
+ * gus_pat.c -- Midi Wavetable Processing library
+ *
+ * Copyright (C) WildMIDI Developers 2001-2015
+ *
+ * This file is part of WildMIDI.
+ *
+ * WildMIDI is free software: you can redistribute and/or modify the player
+ * under the terms of the GNU General Public License and you can redistribute
+ * and/or modify the library under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either version 3 of
+ * the licenses, or(at your option) any later version.
+ *
+ * WildMIDI 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 and
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License and the
+ * GNU Lesser General Public License along with WildMIDI. If not, see
+ * .
*/
-//#include "config.h"
-
#include
#include
#include
@@ -737,6 +732,8 @@ struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) {
};
unsigned long int tmp_loop;
+ /*unused*/fix_release;
+
SAMPLE_CONVERT_DEBUG(__FUNCTION__); SAMPLE_CONVERT_DEBUG(filename);
if ((gus_patch = _WM_BufferFile(filename, &gus_size)) == NULL) {
@@ -839,17 +836,80 @@ struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) {
/*
FIXME: Experimental Hacky Fix
+
+ This looks for "dodgy" release envelope settings that faulty editors
+ may have set and attempts to corrects it.
+ if (fix_release)
+ Lets make this automatic ...
*/
- if (fix_release) {
- if (env_time_table[gus_patch[gus_ptr + 40]]
- < env_time_table[gus_patch[gus_ptr + 41]]) {
- unsigned char tmp_hack_rate = gus_patch[gus_ptr + 41];
- gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 40];
- gus_patch[gus_ptr + 40] = tmp_hack_rate;
+ {
+ /*
+ After studying faulty gus_pats this way may work better
+ Testing to determine if any further adjustments are required
+ */
+ if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 41]]) {
+ unsigned char tmp_hack_rate = 0;
+
+ if (env_time_table[gus_patch[gus_ptr + 41]] < env_time_table[gus_patch[gus_ptr + 42]]) {
+ // 1 2 3
+ tmp_hack_rate = gus_patch[gus_ptr + 40];
+ gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42];
+ gus_patch[gus_ptr + 42] = tmp_hack_rate;
+ } else if (env_time_table[gus_patch[gus_ptr + 41]] == env_time_table[gus_patch[gus_ptr + 42]]) {
+ // 1 2 2
+ tmp_hack_rate = gus_patch[gus_ptr + 40];
+ gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42];
+ gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42];
+ gus_patch[gus_ptr + 42] = tmp_hack_rate;
+
+ } else {
+ if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 42]]) {
+ // 1 3 2
+ tmp_hack_rate = gus_patch[gus_ptr + 40];
+ gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 41];
+ gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42];
+ gus_patch[gus_ptr + 42] = tmp_hack_rate;
+ } else {
+ // 2 3 1 or 1 2 1
+ tmp_hack_rate = gus_patch[gus_ptr + 40];
+ gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 41];
+ gus_patch[gus_ptr + 41] = tmp_hack_rate;
+ }
+ }
+ } else if (env_time_table[gus_patch[gus_ptr + 41]] < env_time_table[gus_patch[gus_ptr + 42]]) {
+ unsigned char tmp_hack_rate = 0;
+
+ if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 42]]) {
+ // 2 1 3
+ tmp_hack_rate = gus_patch[gus_ptr + 40];
+ gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42];
+ gus_patch[gus_ptr + 42] = gus_patch[gus_ptr + 41];
+ gus_patch[gus_ptr + 41] = tmp_hack_rate;
+ } else {
+ // 3 1 2
+ tmp_hack_rate = gus_patch[gus_ptr + 41];
+ gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42];
+ gus_patch[gus_ptr + 42] = tmp_hack_rate;
+ }
}
+
+#if 0
+ if ((env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 41]]) && (env_time_table[gus_patch[gus_ptr + 41]] == env_time_table[gus_patch[gus_ptr + 42]])) {
+ uint8_t tmp_hack_rate = 0;
+ tmp_hack_rate = gus_patch[gus_ptr + 41];
+ gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 40];
+ gus_patch[gus_ptr + 42] = gus_patch[gus_ptr + 40];
+ gus_patch[gus_ptr + 40] = tmp_hack_rate;
+ tmp_hack_rate = gus_patch[gus_ptr + 47];
+ gus_patch[gus_ptr + 47] = gus_patch[gus_ptr + 46];
+ gus_patch[gus_ptr + 48] = gus_patch[gus_ptr + 46];
+ gus_patch[gus_ptr + 46] = tmp_hack_rate;
+ }
+#endif
}
for (i = 0; i < 6; i++) {
+ GUSPAT_INT_DEBUG("Envelope #",i);
if (gus_sample->modes & SAMPLE_ENVELOPE) {
unsigned char env_rate = gus_patch[gus_ptr + 37 + i];
gus_sample->env_target[i] = 16448 * gus_patch[gus_ptr + 43 + i];
@@ -886,6 +946,27 @@ struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) {
return NULL;
}
+ /*
+ Test and set decay expected decay time after a note off
+ NOTE: This sets samples for full range decay
+ */
+ if (gus_sample->modes & SAMPLE_ENVELOPE) {
+ double samples_f = 0.0;
+
+ if (gus_sample->modes & SAMPLE_CLAMPED) {
+ samples_f = (4194301.0 - (float)gus_sample->env_target[5]) / gus_sample->env_rate[5];
+ } else {
+ if (gus_sample->modes & SAMPLE_SUSTAIN) {
+ samples_f = (4194301.0 - (float)gus_sample->env_target[3]) / gus_sample->env_rate[3];
+ samples_f += (float)(gus_sample->env_target[3] - gus_sample->env_target[4]) / gus_sample->env_rate[4];
+ } else {
+ samples_f = (4194301.0 - (float)gus_sample->env_target[4]) / gus_sample->env_rate[4];
+ }
+ samples_f += (float)(gus_sample->env_target[4] - gus_sample->env_target[5]) / gus_sample->env_rate[5];
+ }
+ samples_f += (float)gus_sample->env_target[5] / gus_sample->env_rate[6];
+ }
+
gus_ptr += tmp_cnt;
gus_sample->loop_start = (gus_sample->loop_start << 10)
| (((gus_sample->loop_fraction & 0x0f) << 10) / 16);
diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp
index 0a527ec2a8..5f711bf35c 100644
--- a/src/wildmidi/wildmidi_lib.cpp
+++ b/src/wildmidi/wildmidi_lib.cpp
@@ -116,36 +116,24 @@ struct _note {
unsigned char velocity;
struct _patch *patch;
struct _sample *sample;
- unsigned long int sample_pos;
- unsigned long int sample_inc;
- signed long int env_inc;
+ unsigned int sample_pos;
+ unsigned int sample_inc;
+ signed int env_inc;
unsigned char env;
- signed long int env_level;
+ signed int env_level;
unsigned char modes;
unsigned char hold;
unsigned char active;
struct _note *replay;
struct _note *next;
- unsigned long int vol_lvl;
+ unsigned int left_mix_volume;
+ unsigned int right_mix_volume;
unsigned char is_off;
};
-struct _miditrack {
- unsigned long int length;
- unsigned long int ptr;
- unsigned long int delta;
- unsigned char running_event;
- unsigned char EOT;
-};
-
-struct _mdi_patches {
- struct _patch *patch;
- struct _mdi_patch *next;
-};
-
struct _event_data {
unsigned char channel;
- unsigned long int data;
+ unsigned int data;
};
struct _mdi {
@@ -286,30 +274,70 @@ static signed short int lin_volume[] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72,
878, 886, 894, 903, 911, 919, 927, 935, 943, 951, 959, 967, 975, 983,
991, 999, 1007, 1015, 1024 };
-/* f: pow(( VOLUME / 127.0 ), 2.0 ) * 1024.0 */
-static signed short int sqr_volume[] = { 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 9,
- 10, 12, 14, 16, 18, 20, 22, 25, 27, 30, 33, 36, 39, 42, 46, 49, 53, 57,
- 61, 65, 69, 73, 77, 82, 86, 91, 96, 101, 106, 111, 117, 122, 128, 134,
- 140, 146, 152, 158, 165, 171, 178, 185, 192, 199, 206, 213, 221, 228,
- 236, 244, 251, 260, 268, 276, 284, 293, 302, 311, 320, 329, 338, 347,
- 357, 366, 376, 386, 396, 406, 416, 426, 437, 447, 458, 469, 480, 491,
- 502, 514, 525, 537, 549, 560, 572, 585, 597, 609, 622, 634, 647, 660,
- 673, 686, 699, 713, 726, 740, 754, 768, 782, 796, 810, 825, 839, 854,
- 869, 884, 899, 914, 929, 944, 960, 976, 992, 1007, 1024 };
+/* f: As per midi 2 standard */
+static float dBm_volume[] = { -999999.999999f, -84.15214884f, -72.11094901f,
+ -65.06729865f, -60.06974919f, -56.19334866f, -53.02609882f, -50.34822724f,
+ -48.02854936f, -45.98244846f, -44.15214884f, -42.49644143f, -40.984899f,
+ -39.59441475f, -38.30702741f, -37.10849848f, -35.98734953f, -34.93419198f,
+ -33.94124863f, -33.0020048f, -32.11094901f, -31.26337705f, -30.45524161f,
+ -29.6830354f, -28.94369917f, -28.23454849f, -27.55321492f, -26.89759827f,
+ -26.26582758f, -25.65622892f, -25.06729865f, -24.49768108f, -23.94614971f,
+ -23.41159124f, -22.89299216f, -22.38942706f, -21.90004881f, -21.42407988f,
+ -20.96080497f, -20.50956456f, -20.06974919f, -19.64079457f, -19.22217722f,
+ -18.81341062f, -18.41404178f, -18.02364829f, -17.64183557f, -17.26823452f,
+ -16.90249934f, -16.54430564f, -16.19334866f, -15.84934179f, -15.51201509f,
+ -15.18111405f, -14.85639845f, -14.53764126f, -14.22462776f, -13.91715461f,
+ -13.6150291f, -13.31806837f, -13.02609882f, -12.73895544f, -12.45648126f,
+ -12.17852686f, -11.90494988f, -11.63561457f, -11.37039142f, -11.10915673f,
+ -10.85179233f, -10.59818521f, -10.34822724f, -10.10181489f, -9.858848981f,
+ -9.619234433f, -9.382880049f, -9.149698303f, -8.919605147f, -8.692519831f,
+ -8.468364731f, -8.247065187f, -8.028549359f, -7.812748083f, -7.599594743f,
+ -7.389025143f, -7.180977396f, -6.97539181f, -6.772210788f, -6.571378733f,
+ -6.372841952f, -6.176548572f, -5.982448461f, -5.790493145f, -5.600635744f,
+ -5.412830896f, -5.227034694f, -5.043204627f, -4.861299517f, -4.681279468f,
+ -4.503105811f, -4.326741054f, -4.152148838f, -3.979293887f, -3.808141968f,
+ -3.63865985f, -3.470815266f, -3.304576875f, -3.139914228f, -2.976797731f,
+ -2.815198619f, -2.655088921f, -2.496441432f, -2.339229687f, -2.183427931f,
+ -2.029011099f, -1.875954785f, -1.724235224f, -1.573829269f, -1.424714368f,
+ -1.276868546f, -1.130270383f, -0.9848989963f, -0.8407340256f, -0.6977556112f,
+ -0.5559443807f, -0.4152814317f, -0.2757483179f, -0.1373270335f, 0 };
-/* f: pow(( VOLUME / 127.0 ), 0.5 ) * 1024.0 */
-static signed short int pan_volume[] = { 0, 90, 128, 157, 181, 203, 222, 240,
- 257, 272, 287, 301, 314, 327, 339, 351, 363, 374, 385, 396, 406, 416,
- 426, 435, 445, 454, 463, 472, 480, 489, 497, 505, 514, 521, 529, 537,
- 545, 552, 560, 567, 574, 581, 588, 595, 602, 609, 616, 622, 629, 636,
- 642, 648, 655, 661, 667, 673, 679, 686, 692, 697, 703, 709, 715, 721,
- 726, 732, 738, 743, 749, 754, 760, 765, 771, 776, 781, 786, 792, 797,
- 802, 807, 812, 817, 822, 827, 832, 837, 842, 847, 852, 857, 862, 866,
- 871, 876, 880, 885, 890, 894, 899, 904, 908, 913, 917, 922, 926, 931,
- 935, 939, 944, 948, 953, 957, 961, 965, 970, 974, 978, 982, 987, 991,
- 995, 999, 1003, 1007, 1011, 1015, 1019, 1024 };
+/* f: As per midi 2 standard */
+static float dBm_pan_volume[127] = {
+ -999999.999999f, -87.6945020928f, -73.8331126923f, -65.7264009888f,
+ -59.9763864074f, -55.5181788833f, -51.8774481743f, -48.8011722841f,
+ -46.1383198371f, -43.7914727130f, -41.6941147218f, -39.7988027954f,
+ -38.0705069530f, -36.4826252703f, -35.0144798827f, -33.6496789707f,
+ -32.3750084716f, -31.1796603753f, -30.0546819321f, -28.9925739783f,
+ -27.9869924122f, -27.0325225804f, -26.1245061976f, -25.2589067713f,
+ -24.4322036893f, -23.6413079424f, -22.8834943857f, -22.1563467917f,
+ -21.4577129008f, -20.7856673630f, -20.1384809653f, -19.5145949062f,
+ -18.9125991563f, -18.3312141503f, -17.7692752119f, -17.2257192381f,
+ -16.6995732597f, -16.1899445690f, -15.6960121652f, -15.2170193110f,
+ -14.7522670314f, -14.3011084168f, -13.8629436112f, -13.4372153915f,
+ -13.0234052546f, -12.6210299451f, -12.2296383638f, -11.8488088095f,
+ -11.4781465116f, -11.1172814164f, -10.7658661983f, -10.4235744668f,
+ -10.0900991491f, -9.7651510261f, -9.4484574055f, -9.1397609172f,
+ -8.8388184168f, -8.5453999868f, -8.2592880250f, -7.9802764101f,
+ -7.7081697387f, -7.4427826248f, -7.1839390567f, -6.9314718056f,
+ -6.6852218807f, -6.4450380272f, -6.2107762624f, -5.9822994468f,
+ -5.7594768878f, -5.5421839719f, -5.3303018237f, -5.1237169899f,
+ -4.9223211445f, -4.7260108155f, -4.5346871303f, -4.3482555779f,
+ -4.1666257875f, -3.9897113219f, -3.8174294843f, -3.6497011373f,
+ -3.4864505345f, -3.3276051620f, -3.1730955900f, -3.0228553340f,
+ -2.8768207245f, -2.7349307844f, -2.5971271143f, -2.4633537845f,
+ -2.3335572335f, -2.2076861725f, -2.0856914960f, -1.9675261968f,
+ -1.8531452871f, -1.7425057233f, -1.6355663356f, -1.5322877618f,
+ -1.4326323846f, -1.3365642732f, -1.2440491272f, -1.1550542250f,
+ -1.0695483746f, -0.9875018671f, -0.9088864335f, -0.8336752037f,
+ -0.7618426682f, -0.6933646420f, -0.6282182304f, -0.5663817981f,
+ -0.5078349388f, -0.4525584478f, -0.4005342959f, -0.3517456058f,
+ -0.3061766293f, -0.2638127266f, -0.2246403475f, -0.1886470134f,
+ -0.1558213016f, -0.1261528303f, -0.0996322457f, -0.0762512098f,
+ -0.0560023899f, -0.0388794497f, -0.0248770409f, -0.0139907967f,
+ -0.0062173263f, -0.0015542108f, 0.0000000000f };
-static unsigned long int freq_table[] = { 837201792, 837685632, 838169728,
+static unsigned int freq_table[] = { 837201792, 837685632, 838169728,
838653568, 839138240, 839623232, 840108480, 840593984, 841079680,
841565184, 842051648, 842538240, 843025152, 843512320, 843999232,
844486976, 844975040, 845463360, 845951936, 846440320, 846929536,
@@ -573,7 +601,7 @@ static inline int wm_isdigit(int c) {
#define TOKEN_CNT_INC 8
static char** WM_LC_Tokenize_Line(char *line_data)
{
- int line_length = strlen(line_data);
+ int line_length = (int)strlen(line_data);
int token_data_length = 0;
int line_ofs = 0;
int token_start = 0;
@@ -1191,7 +1219,6 @@ static int load_sample(struct _patch *sample_patch) {
samp_max = tmp_sample->data[i];
if (tmp_sample->data[i] < samp_min)
samp_min = tmp_sample->data[i];
-
}
if (samp_max > tmp_max)
tmp_max = samp_max;
@@ -1386,47 +1413,121 @@ get_sample_data(struct _patch *sample_patch, unsigned long int freq) {
return return_sample;
}
+/* Should be called in any function that effects note volumes */
+void _WM_AdjustNoteVolumes(struct _mdi *mdi, unsigned char ch, struct _note *nte) {
+ double premix_dBm;
+ double premix_lin;
+ int pan_ofs;
+ double premix_dBm_left;
+ double premix_dBm_right;
+ double premix_left;
+ double premix_right;
+ double volume_adj;
+ unsigned vol_ofs;
+
+ /*
+ Pointless CPU heating checks to shoosh up a compiler
+ */
+ if (ch > 0x0f) ch = 0x0f;
+
+ pan_ofs = mdi->channel[ch].balance + mdi->channel[ch].pan - 64;
+
+ vol_ofs = (nte->velocity * ((mdi->channel[ch].expression * mdi->channel[ch].volume) / 127)) / 127;
+
+ /*
+ This value is to reduce the chance of clipping.
+ Higher value means lower overall volume,
+ Lower value means higher overall volume.
+ NOTE: The lower the value the higher the chance of clipping.
+ FIXME: Still needs tuning. Clipping heard at a value of 3.75
+ */
+#define VOL_DIVISOR 4.0
+ volume_adj = ((float)WM_MasterVolume / 1024.0) / VOL_DIVISOR;
+
+ // Pan 0 and 1 are both hard left so 64 can be centered
+ if (pan_ofs > 127) pan_ofs = 127;
+ if (--pan_ofs < 0) pan_ofs = 0;
+ premix_dBm_left = dBm_pan_volume[126-pan_ofs];
+ premix_dBm_right = dBm_pan_volume[pan_ofs];
+
+ if (mdi->info.mixer_options & WM_MO_LOG_VOLUME) {
+ premix_dBm = dBm_volume[vol_ofs];
+
+ premix_dBm_left += premix_dBm;
+ premix_dBm_right += premix_dBm;
+
+ premix_left = (pow(10.0,(premix_dBm_left / 20.0))) * volume_adj;
+ premix_right = (pow(10.0,(premix_dBm_right / 20.0))) * volume_adj;
+ } else {
+ premix_lin = (float)(lin_volume[vol_ofs]) / 1024.0;
+
+ premix_left = premix_lin * pow(10.0, (premix_dBm_left / 20)) * volume_adj;
+ premix_right = premix_lin * pow(10.0, (premix_dBm_right / 20)) * volume_adj;
+ }
+ nte->left_mix_volume = (int)(premix_left * 1024.0);
+ nte->right_mix_volume = (int)(premix_right * 1024.0);
+}
+
+/* Should be called in any function that effects channel volumes */
+/* Calling this function with a value > 15 will make it adjust notes on all channels */
+void _WM_AdjustChannelVolumes(struct _mdi *mdi, unsigned char ch) {
+ struct _note *nte = mdi->note;
+ if (nte != NULL) {
+ do {
+ if (ch <= 15) {
+ if ((nte->noteid >> 8) == ch) {
+ goto _DO_ADJUST;
+ }
+ } else {
+ _DO_ADJUST:
+ _WM_AdjustNoteVolumes(mdi, ch, nte);
+ if (nte->replay) _WM_AdjustNoteVolumes(mdi, ch, nte->replay);
+ }
+ nte = nte->next;
+ } while (nte != NULL);
+ }
+}
+
static void do_note_off_extra(struct _note *nte) {
nte->is_off = 0;
- if (nte->hold) {
- nte->hold |= HOLD_OFF;
- } else {
- if (!(nte->modes & SAMPLE_ENVELOPE)) {
- if (nte->modes & SAMPLE_LOOP) {
- nte->modes ^= SAMPLE_LOOP;
- }
- nte->env_inc = 0;
- } else if (nte->modes & SAMPLE_CLAMPED) {
- if (nte->env < 5) {
- nte->env = 5;
- if (nte->env_level > nte->sample->env_target[5]) {
- nte->env_inc = -nte->sample->env_rate[5];
- } else {
- nte->env_inc = nte->sample->env_rate[5];
- }
- }
-#if 1
- } else if (nte->modes & SAMPLE_SUSTAIN) {
- if (nte->env < 3) {
- nte->env = 3;
- if (nte->env_level > nte->sample->env_target[3]) {
- nte->env_inc = -nte->sample->env_rate[3];
- } else {
- nte->env_inc = nte->sample->env_rate[3];
- }
- }
-#endif
- } else if (nte->env < 4) {
- nte->env = 4;
- if (nte->env_level > nte->sample->env_target[4]) {
- nte->env_inc = -nte->sample->env_rate[4];
+ if (!(nte->modes & SAMPLE_ENVELOPE)) {
+ if (nte->modes & SAMPLE_LOOP) {
+ nte->modes ^= SAMPLE_LOOP;
+ }
+ nte->env_inc = 0;
+
+ } else if (nte->hold) {
+ nte->hold |= HOLD_OFF;
+
+ } else if (nte->modes & SAMPLE_SUSTAIN) {
+ if (nte->env < 3) {
+ nte->env = 3;
+ if (nte->env_level > nte->sample->env_target[3]) {
+ nte->env_inc = -nte->sample->env_rate[3];
} else {
- nte->env_inc = nte->sample->env_rate[4];
+ nte->env_inc = nte->sample->env_rate[3];
}
}
+
+ } else if (nte->modes & SAMPLE_CLAMPED) {
+ if (nte->env < 5) {
+ nte->env = 5;
+ if (nte->env_level > nte->sample->env_target[5]) {
+ nte->env_inc = -nte->sample->env_rate[5];
+ } else {
+ nte->env_inc = nte->sample->env_rate[5];
+ }
+ }
+ } else if (nte->env < 4) {
+ nte->env = 4;
+ if (nte->env_level > nte->sample->env_target[4]) {
+ nte->env_inc = -nte->sample->env_rate[4];
+ } else {
+ nte->env_inc = nte->sample->env_rate[4];
+ }
}
}
@@ -1447,7 +1548,10 @@ static void do_note_off(struct _mdi *mdi, struct _event_data *data) {
return;
}
- if (nte->env == 0) {
+ if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env == 0)) {
+ // This is a fix for notes that end before the
+ // initial step of the envelope has completed
+ // making it impossible to hear them at times.
nte->is_off = 1;
} else {
do_note_off_extra(nte);
@@ -1475,24 +1579,6 @@ static inline unsigned long int get_inc(struct _mdi *mdi, struct _note *nte) {
/ nte->sample->inc_div));
}
-static inline unsigned long int get_volume(struct _mdi *mdi, unsigned char ch,
- struct _note *nte) {
- signed long int volume;
-
- if (mdi->info.mixer_options & WM_MO_LOG_VOLUME) {
- volume = (sqr_volume[mdi->channel[ch].volume]
- * sqr_volume[mdi->channel[ch].expression]
- * sqr_volume[nte->velocity]) / 1048576;
- } else {
- volume = (lin_volume[mdi->channel[ch].volume]
- * lin_volume[mdi->channel[ch].expression]
- * lin_volume[nte->velocity]) / 1048576;
- }
-
- volume = volume * nte->patch->amp / 100;
- return (volume);
-}
-
static void do_note_on(struct _mdi *mdi, struct _event_data *data) {
struct _note *nte;
struct _note *prev_nte;
@@ -1502,7 +1588,7 @@ static void do_note_on(struct _mdi *mdi, struct _event_data *data) {
struct _sample *sample;
unsigned char ch = data->channel;
unsigned char note = (unsigned char)(data->data >> 8);
- unsigned char velocity = (data->data & 0xFF);
+ unsigned char velocity = (unsigned char)(data->data & 0xFF);
if (velocity == 0x00) {
do_note_off(mdi, data);
@@ -1580,9 +1666,9 @@ static void do_note_on(struct _mdi *mdi, struct _event_data *data) {
nte->env_level = 0;
nte->modes = sample->modes;
nte->hold = mdi->channel[ch].hold;
- nte->vol_lvl = get_volume(mdi, ch, nte);
nte->replay = NULL;
nte->is_off = 0;
+ _WM_AdjustNoteVolumes(mdi, ch, nte);
}
static void do_aftertouch(struct _mdi *mdi, struct _event_data *data) {
@@ -1599,40 +1685,14 @@ static void do_aftertouch(struct _mdi *mdi, struct _event_data *data) {
}
}
- nte->velocity = data->data & 0xff;
- nte->vol_lvl = get_volume(mdi, ch, nte);
-
+ nte->velocity = (unsigned char)data->data;
+ _WM_AdjustNoteVolumes(mdi, ch, nte);
if (nte->replay) {
- nte->replay->velocity = data->data & 0xff;
- nte->replay->vol_lvl = get_volume(mdi, ch, nte->replay);
+ nte->replay->velocity = (unsigned char)data->data;
+ _WM_AdjustNoteVolumes(mdi, ch, nte->replay);
}
}
-static void do_pan_adjust(struct _mdi *mdi, unsigned char ch) {
- signed short int pan_adjust = mdi->channel[ch].balance
- + mdi->channel[ch].pan;
- signed short int left, right;
- int amp = 32;
-
- if (pan_adjust > 63) {
- pan_adjust = 63;
- } else if (pan_adjust < -64) {
- pan_adjust = -64;
- }
-
- pan_adjust += 64;
-/* if (mdi->info.mixer_options & WM_MO_LOG_VOLUME) {*/
- left = (pan_volume[127 - pan_adjust] * WM_MasterVolume * amp) / 1048576;
- right = (pan_volume[pan_adjust] * WM_MasterVolume * amp) / 1048576;
-/* } else {
- left = (lin_volume[127 - pan_adjust] * WM_MasterVolume * amp) / 1048576;
- right= (lin_volume[pan_adjust] * WM_MasterVolume * amp) / 1048576;
- }*/
-
- mdi->channel[ch].left_adjust = left;
- mdi->channel[ch].right_adjust = right;
-}
-
static void do_control_bank_select(struct _mdi *mdi, struct _event_data *data) {
unsigned char ch = data->channel;
mdi->channel[ch].bank = (unsigned char)data->data;
@@ -1658,33 +1718,22 @@ static void do_control_channel_volume(struct _mdi *mdi,
unsigned char ch = data->channel;
mdi->channel[ch].volume = (unsigned char)data->data;
-
- if (note_data) {
- do {
- if ((note_data->noteid >> 8) == ch) {
- note_data->vol_lvl = get_volume(mdi, ch, note_data);
- if (note_data->replay)
- note_data->replay->vol_lvl = get_volume(mdi, ch,
- note_data->replay);
- }
- note_data = note_data->next;
- } while (note_data);
- }
+ _WM_AdjustChannelVolumes(mdi, ch);
}
static void do_control_channel_balance(struct _mdi *mdi,
struct _event_data *data) {
unsigned char ch = data->channel;
- mdi->channel[ch].balance = (signed char)(data->data - 64);
- do_pan_adjust(mdi, ch);
+ mdi->channel[ch].balance = (signed char)(data->data);
+ _WM_AdjustChannelVolumes(mdi, ch);
}
static void do_control_channel_pan(struct _mdi *mdi, struct _event_data *data) {
unsigned char ch = data->channel;
- mdi->channel[ch].pan = (signed char)(data->data - 64);
- do_pan_adjust(mdi, ch);
+ mdi->channel[ch].pan = (signed char)(data->data);
+ _WM_AdjustChannelVolumes(mdi, ch);
}
static void do_control_channel_expression(struct _mdi *mdi,
@@ -1693,18 +1742,7 @@ static void do_control_channel_expression(struct _mdi *mdi,
unsigned char ch = data->channel;
mdi->channel[ch].expression = (unsigned char)data->data;
-
- if (note_data) {
- do {
- if ((note_data->noteid >> 8) == ch) {
- note_data->vol_lvl = get_volume(mdi, ch, note_data);
- if (note_data->replay)
- note_data->replay->vol_lvl = get_volume(mdi, ch,
- note_data->replay);
- }
- note_data = note_data->next;
- } while (note_data);
- }
+ _WM_AdjustChannelVolumes(mdi, ch);
}
static void do_control_data_entry_fine(struct _mdi *mdi,
@@ -1794,9 +1832,19 @@ static void do_control_data_decrement(struct _mdi *mdi,
mdi->channel[ch].pitch_range--;
}
}
-static void do_control_non_registered_param(struct _mdi *mdi,
+static void do_control_non_registered_param_fine(struct _mdi *mdi,
+ struct _event_data *data) {
+ unsigned char ch = data->channel;
+ mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x3F80)
+ | data->data;
+ mdi->channel[ch].reg_non = 1;
+}
+
+static void do_control_non_registered_param_course(struct _mdi *mdi,
struct _event_data *data) {
unsigned char ch = data->channel;
+ mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x7F)
+ | (data->data << 7);
mdi->channel[ch].reg_non = 1;
}
@@ -1841,33 +1889,13 @@ static void do_control_channel_controllers_off(struct _mdi *mdi,
mdi->channel[ch].expression = 127;
mdi->channel[ch].pressure = 127;
- mdi->channel[ch].volume = 100;
- mdi->channel[ch].pan = 0;
- mdi->channel[ch].balance = 0;
mdi->channel[ch].reg_data = 0xffff;
mdi->channel[ch].pitch_range = 200;
mdi->channel[ch].pitch = 0;
mdi->channel[ch].pitch_adjust = 0;
mdi->channel[ch].hold = 0;
- do_pan_adjust(mdi, ch);
- if (note_data) {
- do {
- if ((note_data->noteid >> 8) == ch) {
- note_data->sample_inc = get_inc(mdi, note_data);
- note_data->velocity = 0;
- note_data->vol_lvl = get_volume(mdi, ch, note_data);
- note_data->hold = 0;
-
- if (note_data->replay) {
- note_data->replay->velocity = (unsigned char)data->data;
- note_data->replay->vol_lvl = get_volume(mdi, ch,
- note_data->replay);
- }
- }
- note_data = note_data->next;
- } while (note_data);
- }
+ _WM_AdjustChannelVolumes(mdi, ch);
}
static void do_control_channel_notes_off(struct _mdi *mdi,
@@ -1919,20 +1947,16 @@ static void do_channel_pressure(struct _mdi *mdi, struct _event_data *data) {
MIDI_EVENT_DEBUG(__FUNCTION__,ch);
- if (note_data) {
- do {
- if ((note_data->noteid >> 8) == ch) {
- note_data->velocity = (unsigned char)data->data;
- note_data->vol_lvl = get_volume(mdi, ch, note_data);
-
- if (note_data->replay) {
- note_data->replay->velocity = (unsigned char)data->data;
- note_data->replay->vol_lvl = get_volume(mdi, ch,
- note_data->replay);
- }
+ while (note_data) {
+ if ((note_data->noteid >> 8) == ch) {
+ note_data->velocity = (unsigned char)data->data;
+ _WM_AdjustNoteVolumes(mdi, ch, note_data);
+ if (note_data->replay) {
+ note_data->replay->velocity = (unsigned char)data->data;
+ _WM_AdjustNoteVolumes(mdi, ch, note_data->replay);
}
- note_data = note_data->next;
- } while (note_data);
+ }
+ note_data = note_data->next;
}
}
@@ -1976,7 +2000,7 @@ static void do_sysex_roland_drum_track(struct _mdi *mdi,
}
}
-static void do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) {
+static void do_sysex_gm_reset(struct _mdi *mdi, struct _event_data *data) {
int i;
for (i = 0; i < 16; i++) {
mdi->channel[i].bank = 0;
@@ -1989,20 +2013,29 @@ static void do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) {
mdi->channel[i].volume = 100;
mdi->channel[i].pressure = 127;
mdi->channel[i].expression = 127;
- mdi->channel[i].balance = 0;
- mdi->channel[i].pan = 0;
- mdi->channel[i].left_adjust = 1;
- mdi->channel[i].right_adjust = 1;
+ mdi->channel[i].balance = 64;
+ mdi->channel[i].pan = 64;
mdi->channel[i].pitch = 0;
mdi->channel[i].pitch_range = 200;
mdi->channel[i].reg_data = 0xFFFF;
mdi->channel[i].isdrum = 0;
- do_pan_adjust(mdi, i);
}
+ /* I would not expect notes to be active when this event
+ triggers but we'll adjust active notes as well just in case */
+ _WM_AdjustChannelVolumes(mdi,16); // A setting > 15 adjusts all channels
+
mdi->channel[9].isdrum = 1;
UNUSED(data); /* NOOP, to please the compiler gods */
}
+static void do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) {
+ do_sysex_gm_reset(mdi, data);
+}
+
+static void do_sysex_yamaha_reset(struct _mdi *mdi, struct _event_data *data) {
+ do_sysex_gm_reset(mdi, data);
+}
+
static int add_handle(void * handle) {
struct _hndl *tmp_handle = NULL;
@@ -2084,56 +2117,11 @@ static void freeMDI(struct _mdi *mdi) {
free(mdi);
}
-static unsigned long int get_decay_samples(struct _patch *patch, unsigned char note) {
-
- struct _sample *sample = NULL;
- unsigned long int freq = 0;
- unsigned long int decay_samples = 0;
-
- if (patch == NULL)
- return 0;
-
- /* first get the freq we need so we can check the right sample */
- if (patch->patchid & 0x80) {
- /* is a drum patch */
- if (patch->note) {
- freq = freq_table[(patch->note % 12) * 100]
- >> (10 - (patch->note / 12));
- } else {
- freq = freq_table[(note % 12) * 100] >> (10 - (note / 12));
- }
- } else {
- freq = freq_table[(note % 12) * 100] >> (10 - (note / 12));
- }
-
- /* get the sample */
- sample = get_sample_data(patch, (freq / 100));
- if (sample == NULL)
- return 0;
-
- if (patch->patchid & 0x80) {
- float sratedata = ((float) sample->rate / (float) _WM_SampleRate)
- * (float) (sample->data_length >> 10);
- decay_samples = (unsigned long int) sratedata;
- /* printf("Drums (%i / %i) * %lu = %f\n", sample->rate, _WM_SampleRate, (sample->data_length >> 10), sratedata);*/
- } else if (sample->modes & SAMPLE_CLAMPED) {
- decay_samples = (4194303 / sample->env_rate[5]);
- /* printf("clamped 4194303 / %lu = %lu\n", sample->env_rate[5], decay_samples);*/
- } else {
- decay_samples =
- ((4194303 - sample->env_target[4]) / sample->env_rate[4])
- + (sample->env_target[4] / sample->env_rate[5]);
- /* printf("NOT clamped ((4194303 - %lu) / %lu) + (%lu / %lu)) = %lu\n", sample->env_target[4], sample->env_rate[4], sample->env_target[4], sample->env_rate[5], decay_samples);*/
- }
- return decay_samples;
-}
-
static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count)
{
struct _mdi *mdi = (struct _mdi *)handle;
unsigned long int data_pos;
signed int premix, left_mix, right_mix;
- signed int vol_mul;
struct _note *note_data = NULL;
do {
@@ -2147,20 +2135,11 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count)
* ===================
*/
data_pos = note_data->sample_pos >> FPBITS;
- vol_mul = ((note_data->vol_lvl
- * (note_data->env_level >> 12)) >> FPBITS);
+ premix = ((note_data->sample->data[data_pos] + (((note_data->sample->data[data_pos + 1] - note_data->sample->data[data_pos]) * (int)(note_data->sample_pos & FPMASK)) / 1024)) * (note_data->env_level >> 12)) / 1024;
- premix = (note_data->sample->data[data_pos]
- + ((note_data->sample->data[data_pos + 1]
- - note_data->sample->data[data_pos])
- * (signed long int) (note_data->sample_pos
- & FPMASK)>> FPBITS)) * vol_mul
- / 1024;
- left_mix += premix
- * mdi->channel[note_data->noteid >> 8].left_adjust;
- right_mix += premix
- * mdi->channel[note_data->noteid >> 8].right_adjust;
+ left_mix += (premix * (int)note_data->left_mix_volume) / 1024;
+ right_mix += (premix * (int)note_data->right_mix_volume) / 1024;
/*
* ========================
@@ -2168,19 +2147,16 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count)
* ========================
*/
note_data->sample_pos += note_data->sample_inc;
- if (note_data->sample_pos > note_data->sample->loop_end) {
- if (note_data->modes & SAMPLE_LOOP) {
+ if (note_data->modes & SAMPLE_LOOP) {
+ if (note_data->sample_pos > note_data->sample->loop_end) {
note_data->sample_pos =
- note_data->sample->loop_start
- + ((note_data->sample_pos
- - note_data->sample->loop_start)
- % note_data->sample->loop_size);
- } else if (note_data->sample_pos >= note_data->sample->data_length) {
- if (note_data->replay == NULL) {
- goto KILL_NOTE;
- }
- goto RESTART_NOTE;
+ note_data->sample->loop_start
+ + ((note_data->sample_pos
+ - note_data->sample->loop_start)
+ % note_data->sample->loop_size);
}
+ } else if (note_data->sample_pos >= note_data->sample->data_length) {
+ goto END_THIS_NOTE;
}
if (note_data->env_inc == 0) {
@@ -2189,35 +2165,32 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count)
}
note_data->env_level += note_data->env_inc;
- if (note_data->env_level > 4194304) {
- note_data->env_level =
- note_data->sample->env_target[note_data->env];
- }
- if (((note_data->env_inc < 0)
- && (note_data->env_level
- > note_data->sample->env_target[note_data->env]))
- || ((note_data->env_inc > 0)
- && (note_data->env_level
- < note_data->sample->env_target[note_data->env])))
- {
- note_data = note_data->next;
- continue;
+ if (note_data->env_inc < 0) {
+ if (note_data->env_level > note_data->sample->env_target[note_data->env]) {
+ note_data = note_data->next;
+ continue;
+ }
+ } else if (note_data->env_inc > 0) {
+ if (note_data->env_level < note_data->sample->env_target[note_data->env]) {
+ note_data = note_data->next;
+ continue;
+ }
}
+ // Yes could have a condition here but
+ // it would create another bottleneck
note_data->env_level =
note_data->sample->env_target[note_data->env];
switch (note_data->env) {
case 0:
-#if 0
if (!(note_data->modes & SAMPLE_ENVELOPE)) {
note_data->env_inc = 0;
note_data = note_data->next;
continue;
}
-#endif
break;
case 2:
- if (note_data->modes & SAMPLE_SUSTAIN) {
+ if (note_data->modes & SAMPLE_SUSTAIN /*|| note_data->hold*/) {
note_data->env_inc = 0;
note_data = note_data->next;
continue;
@@ -2236,7 +2209,7 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count)
break;
case 5:
if (note_data->env_level == 0) {
- goto KILL_NOTE;
+ goto END_THIS_NOTE;
}
/* sample release */
if (note_data->modes & SAMPLE_LOOP)
@@ -2245,8 +2218,9 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count)
note_data = note_data->next;
continue;
case 6:
+ END_THIS_NOTE:
if (note_data->replay != NULL) {
- RESTART_NOTE: note_data->active = 0;
+ note_data->active = 0;
{
struct _note *prev_note = NULL;
struct _note *nte_array = mdi->note;
@@ -2267,7 +2241,7 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count)
note_data->active = 1;
}
} else {
- KILL_NOTE: note_data->active = 0;
+ note_data->active = 0;
{
struct _note *prev_note = NULL;
struct _note *nte_array = mdi->note;
@@ -2312,10 +2286,7 @@ static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count)
* mix the channels together
* =========================
*/
- left_mix /= 1024;
- right_mix /= 1024;
}
-
*buffer++ = left_mix;
*buffer++ = right_mix;
} while (--count);
@@ -2329,7 +2300,6 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count)
struct _mdi *mdi = (struct _mdi *)handle;
unsigned long int data_pos;
signed int premix, left_mix, right_mix;
- signed int vol_mul;
struct _note *note_data = NULL;
signed short int *sptr;
double y, xd;
@@ -2348,8 +2318,6 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count)
* ===================
*/
data_pos = note_data->sample_pos >> FPBITS;
- vol_mul = ((note_data->vol_lvl
- * (note_data->env_level >> 12)) >> FPBITS);
/* check to see if we're near one of the ends */
left = data_pos;
@@ -2389,12 +2357,10 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count)
} while (gptr <= gend);
}
- premix = (long) (y * vol_mul / 1024);
+ premix = (int)((y * (note_data->env_level >> 12)) / 1024);
- left_mix += premix
- * mdi->channel[note_data->noteid >> 8].left_adjust;
- right_mix += premix
- * mdi->channel[note_data->noteid >> 8].right_adjust;
+ left_mix += (premix * (int)note_data->left_mix_volume) / 1024;
+ right_mix += (premix * (int)note_data->right_mix_volume) / 1024;
/*
* ========================
@@ -2411,10 +2377,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count)
- note_data->sample->loop_start)
% note_data->sample->loop_size);
} else if (note_data->sample_pos >= note_data->sample->data_length) {
- if (note_data->replay == NULL) {
- goto KILL_NOTE;
- }
- goto RESTART_NOTE;
+ goto END_THIS_NOTE;
}
}
@@ -2424,33 +2387,32 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count)
}
note_data->env_level += note_data->env_inc;
- if (note_data->env_level > 4194304) {
- note_data->env_level =
- note_data->sample->env_target[note_data->env];
- }
- if (
- ((note_data->env_inc < 0)
- && (note_data->env_level
- > note_data->sample->env_target[note_data->env]))
- || ((note_data->env_inc > 0)
- && (note_data->env_level
- < note_data->sample->env_target[note_data->env]))
- ) {
- note_data = note_data->next;
- continue;
+ if (note_data->env_inc < 0) {
+ if (note_data->env_level
+ > note_data->sample->env_target[note_data->env]) {
+ note_data = note_data->next;
+ continue;
+ }
+ } else if (note_data->env_inc > 0) {
+ if (note_data->env_level
+ < note_data->sample->env_target[note_data->env]) {
+ note_data = note_data->next;
+ continue;
+ }
}
+ // Yes could have a condition here but
+ // it would create another bottleneck
+
note_data->env_level =
note_data->sample->env_target[note_data->env];
switch (note_data->env) {
case 0:
-#if 0
if (!(note_data->modes & SAMPLE_ENVELOPE)) {
note_data->env_inc = 0;
note_data = note_data->next;
continue;
}
-#endif
break;
case 2:
if (note_data->modes & SAMPLE_SUSTAIN) {
@@ -2472,7 +2434,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count)
break;
case 5:
if (note_data->env_level == 0) {
- goto KILL_NOTE;
+ goto END_THIS_NOTE;
}
/* sample release */
if (note_data->modes & SAMPLE_LOOP)
@@ -2481,8 +2443,9 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count)
note_data = note_data->next;
continue;
case 6:
+ END_THIS_NOTE:
if (note_data->replay != NULL) {
- RESTART_NOTE: note_data->active = 0;
+ note_data->active = 0;
{
struct _note *prev_note = NULL;
struct _note *nte_array = mdi->note;
@@ -2503,7 +2466,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count)
note_data->active = 1;
}
} else {
- KILL_NOTE: note_data->active = 0;
+ note_data->active = 0;
{
struct _note *prev_note = NULL;
struct _note *nte_array = mdi->note;
@@ -2548,10 +2511,7 @@ static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count)
* mix the channels together
* =========================
*/
- left_mix /= 1024;
- right_mix /= 1024;
}
-
*buffer++ = left_mix;
*buffer++ = right_mix;
} while (--count);
@@ -2644,16 +2604,6 @@ WM_SYMBOL int WildMidi_MasterVolume(unsigned char master_volume) {
WM_MasterVolume = lin_volume[master_volume];
- if (tmp_handle) {
- while (tmp_handle) {
- mdi = (struct _mdi *) tmp_handle->handle;
- for (i = 0; i < 16; i++) {
- do_pan_adjust(mdi, i);
- }
- tmp_handle = tmp_handle->next;
- }
- }
-
return 0;
}
@@ -2734,7 +2684,6 @@ midi *WildMidi_NewMidi() {
WM_SYMBOL int WildMidi_SetOption(midi * handle, unsigned short int options,
unsigned short int setting) {
struct _mdi *mdi;
- int i;
if (!WM_Initialized) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
@@ -2765,22 +2714,8 @@ WM_SYMBOL int WildMidi_SetOption(midi * handle, unsigned short int options,
| (options & setting));
if (options & WM_MO_LOG_VOLUME) {
- struct _note *note_data = mdi->note;
-
- for (i = 0; i < 16; i++) {
- do_pan_adjust(mdi, i);
- }
-
- if (note_data) {
- do {
- note_data->vol_lvl = get_volume(mdi, (note_data->noteid >> 8),
- note_data);
- if (note_data->replay)
- note_data->replay->vol_lvl = get_volume(mdi,
- (note_data->noteid >> 8), note_data->replay);
- note_data = note_data->next;
- } while (note_data);
- }
+ _WM_AdjustChannelVolumes(mdi, 16); // Settings greater than 15
+ // adjust all channels
} else if (options & WM_MO_REVERB) {
_WM_reset_reverb(mdi->reverb);
}
@@ -2905,23 +2840,23 @@ void WildMidi_Renderer::ShortEvent(int status, int parm1, int parm2)
ev.data = parm2;
switch (parm1)
{
- case 0: do_control_bank_select(mdi, &ev); break;
- case 6: do_control_data_entry_course(mdi, &ev); break; // [sic]
- case 7: do_control_channel_volume(mdi, &ev); break;
- case 8: do_control_channel_balance(mdi, &ev); break;
- case 10: do_control_channel_pan(mdi, &ev); break;
- case 11: do_control_channel_expression(mdi, &ev); break;
- case 38: do_control_data_entry_fine(mdi, &ev); break;
- case 64: do_control_channel_hold(mdi, &ev); break;
- case 96: do_control_data_increment(mdi, &ev); break;
- case 97: do_control_data_decrement(mdi, &ev); break;
- case 98:
- case 99: do_control_non_registered_param(mdi, &ev); break;
- case 100: do_control_registered_param_fine(mdi, &ev); break;
- case 101: do_control_registered_param_course(mdi, &ev); break; // [sic]
- case 120: do_control_channel_sound_off(mdi, &ev); break;
- case 121: do_control_channel_controllers_off(mdi, &ev); break;
- case 123: do_control_channel_notes_off(mdi, &ev); break;
+ case 0: do_control_bank_select(mdi, &ev); break;
+ case 6: do_control_data_entry_course(mdi, &ev); break; // [sic]
+ case 7: do_control_channel_volume(mdi, &ev); break;
+ case 8: do_control_channel_balance(mdi, &ev); break;
+ case 10: do_control_channel_pan(mdi, &ev); break;
+ case 11: do_control_channel_expression(mdi, &ev); break;
+ case 38: do_control_data_entry_fine(mdi, &ev); break;
+ case 64: do_control_channel_hold(mdi, &ev); break;
+ case 96: do_control_data_increment(mdi, &ev); break;
+ case 97: do_control_data_decrement(mdi, &ev); break;
+ case 98: do_control_non_registered_param_fine(mdi, &ev); break;
+ case 99: do_control_non_registered_param_course(mdi, &ev); break; // [sic]
+ case 100: do_control_registered_param_fine(mdi, &ev); break;
+ case 101: do_control_registered_param_course(mdi, &ev); break; // [sic]
+ case 120: do_control_channel_sound_off(mdi, &ev); break;
+ case 121: do_control_channel_controllers_off(mdi, &ev); break;
+ case 123: do_control_channel_notes_off(mdi, &ev); break;
}
}
}
@@ -2958,7 +2893,7 @@ void WildMidi_Renderer::LongEvent(const unsigned char *data, int len)
{
sysex_ch -= 1;
}
- _event_data ev = { sysex_ch, static_cast(data[8]) };
+ _event_data ev = { sysex_ch, data[8] };
do_sysex_roland_drum_track((_mdi *)handle, &ev);
}
else if (data[6] == 0x00 && data[7] == 0x7F && data[8] == 0x00)
@@ -2967,6 +2902,20 @@ void WildMidi_Renderer::LongEvent(const unsigned char *data, int len)
}
}
}
+ // For non-Roland Sysex messages */
+ else
+ {
+ const unsigned char gm_reset[] = { 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 };
+ const unsigned char yamaha_reset[] = { 0xf0, 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7};
+ if (len == 6 && memcmp(gm_reset, data, 6) == 0)
+ {
+ do_sysex_gm_reset((_mdi *)handle, NULL);
+ }
+ else if (len == 9 && memcmp(yamaha_reset, data, 9) == 0)
+ {
+ do_sysex_yamaha_reset((_mdi *)handle, NULL);
+ }
+ }
}
void WildMidi_Renderer::ComputeOutput(float *fbuffer, int len)
diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp
index e232757344..4e3a14c183 100644
--- a/src/win32/fb_d3d9.cpp
+++ b/src/win32/fb_d3d9.cpp
@@ -72,6 +72,7 @@
#include "v_palette.h"
#include "w_wad.h"
#include "r_data/colormaps.h"
+#include "SkylineBinPack.h"
// MACROS ------------------------------------------------------------------
@@ -84,15 +85,19 @@
// The number of quads we can batch together.
#define MAX_QUAD_BATCH (NUM_INDEXES / 6)
+// The default size for a texture atlas.
+#define DEF_ATLAS_WIDTH 512
+#define DEF_ATLAS_HEIGHT 512
+
// TYPES -------------------------------------------------------------------
IMPLEMENT_CLASS(D3DFB)
struct D3DFB::PackedTexture
{
- D3DFB::PackingTexture *Owner;
+ D3DFB::Atlas *Owner;
- PackedTexture *Next, **Prev;
+ PackedTexture **Prev, *Next;
// Pixels this image covers
RECT Area;
@@ -104,23 +109,19 @@ struct D3DFB::PackedTexture
bool Padded;
};
-struct D3DFB::PackingTexture
+struct D3DFB::Atlas
{
- PackingTexture(D3DFB *fb, int width, int height, D3DFORMAT format);
- ~PackingTexture();
+ Atlas(D3DFB *fb, int width, int height, D3DFORMAT format);
+ ~Atlas();
- PackedTexture *GetBestFit(int width, int height, int &area);
- void AllocateImage(PackedTexture *box, int width, int height);
- PackedTexture *AllocateBox();
- void AddEmptyBox(int left, int top, int right, int bottom);
+ PackedTexture *AllocateImage(const Rect &rect, bool padded);
void FreeBox(PackedTexture *box);
- PackingTexture *Next;
+ SkylineBinPack Packer;
+ Atlas *Next;
IDirect3DTexture9 *Tex;
D3DFORMAT Format;
PackedTexture *UsedList; // Boxes that contain images
- PackedTexture *EmptyList; // Boxes that contain empty space
- PackedTexture *FreeList; // Boxes that are just waiting to be used
int Width, Height;
bool OneUse;
};
@@ -283,7 +284,7 @@ D3DFB::D3DFB (UINT adapter, int width, int height, bool fullscreen)
ScreenWipe = NULL;
InScene = false;
QuadExtra = new BufferedTris[MAX_QUAD_BATCH];
- Packs = NULL;
+ Atlases = NULL;
PixelDoubling = 0;
SkipAt = -1;
CurrRenderTexture = 0;
@@ -496,7 +497,7 @@ void D3DFB::FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, b
bool D3DFB::CreateResources()
{
- Packs = NULL;
+ Atlases = NULL;
if (!Windowed)
{
// Remove the window border in fullscreen mode
@@ -624,8 +625,8 @@ void D3DFB::ReleaseResources ()
delete ScreenWipe;
ScreenWipe = NULL;
}
- PackingTexture *pack, *next;
- for (pack = Packs; pack != NULL; pack = next)
+ Atlas *pack, *next;
+ for (pack = Atlases; pack != NULL; pack = next)
{
next = pack->Next;
delete pack;
@@ -1826,8 +1827,9 @@ IDirect3DTexture9 *D3DFB::GetCurrentScreen(D3DPOOL pool)
//
// D3DFB :: DrawPackedTextures
//
-// DEBUG: Draws the packing textures to the screen, starting with the
-// 1-based packnum.
+// DEBUG: Draws the texture atlases to the screen, starting with the
+// 1-based packnum. Ignores atlases that are flagged for use by one
+// texture only.
//
//==========================================================================
@@ -1835,38 +1837,53 @@ void D3DFB::DrawPackedTextures(int packnum)
{
D3DCOLOR empty_colors[8] =
{
- 0xFFFF9999, 0xFF99FF99, 0xFF9999FF, 0xFFFFFF99,
- 0xFFFF99FF, 0xFF99FFFF, 0xFFFFCC99, 0xFF99CCFF
+ 0x50FF0000, 0x5000FF00, 0x500000FF, 0x50FFFF00,
+ 0x50FF00FF, 0x5000FFFF, 0x50FF8000, 0x500080FF
};
- PackingTexture *pack;
+ Atlas *pack;
int x = 8, y = 8;
if (packnum <= 0)
{
return;
}
- pack = Packs;
+ pack = Atlases;
+ // Find the first texture atlas that is an actual atlas.
while (pack != NULL && pack->OneUse)
- { // Skip textures that aren't used as packing containers
+ { // Skip textures that aren't used as atlases
pack = pack->Next;
}
+ // Skip however many atlases we would have otherwise drawn
+ // until we've skipped of them.
while (pack != NULL && packnum != 1)
{
if (!pack->OneUse)
- { // Skip textures that aren't used as packing containers
+ { // Skip textures that aren't used as atlases
packnum--;
}
pack = pack->Next;
}
+ // Draw atlases until we run out of room on the screen.
while (pack != NULL)
{
if (pack->OneUse)
- { // Skip textures that aren't used as packing containers
+ { // Skip textures that aren't used as atlases
pack = pack->Next;
continue;
}
- AddColorOnlyQuad(x-1, y-1-LBOffsetI, 258, 258, D3DCOLOR_XRGB(255,255,0));
+ AddColorOnlyRect(x-1, y-1-LBOffsetI, 258, 258, D3DCOLOR_XRGB(255,255,0));
+ int back = 0;
+ for (PackedTexture *box = pack->UsedList; box != NULL; box = box->Next)
+ {
+ AddColorOnlyQuad(
+ x + box->Area.left * 256 / pack->Width,
+ y + box->Area.top * 256 / pack->Height,
+ (box->Area.right - box->Area.left) * 256 / pack->Width,
+ (box->Area.bottom - box->Area.top) * 256 / pack->Height, empty_colors[back]);
+ back = (back + 1) & 7;
+ }
+// AddColorOnlyQuad(x, y-LBOffsetI, 256, 256, D3DCOLOR_ARGB(180,0,0,0));
CheckQuadBatch();
@@ -1876,12 +1893,12 @@ void D3DFB::DrawPackedTextures(int packnum)
quad->Group1 = 0;
if (pack->Format == D3DFMT_L8/* && !tex->IsGray*/)
{
- quad->Flags = BQF_WrapUV | BQF_GamePalette | BQF_DisableAlphaTest;
+ quad->Flags = BQF_WrapUV | BQF_GamePalette/* | BQF_DisableAlphaTest*/;
quad->ShaderNum = BQS_PalTex;
}
else
{
- quad->Flags = BQF_WrapUV | BQF_DisableAlphaTest;
+ quad->Flags = BQF_WrapUV/* | BQF_DisableAlphaTest*/;
quad->ShaderNum = BQS_Plain;
}
quad->Palette = NULL;
@@ -1941,16 +1958,6 @@ void D3DFB::DrawPackedTextures(int packnum)
VertexPos += 4;
IndexPos += 6;
- // Draw entries in the empty list.
- PackedTexture *box;
- int emptynum;
- for (box = pack->EmptyList, emptynum = 0; box != NULL; box = box->Next, emptynum++)
- {
- AddColorOnlyQuad(x + box->Area.left, y + box->Area.top - LBOffsetI,
- box->Area.right - box->Area.left, box->Area.bottom - box->Area.top,
- empty_colors[emptynum & 7]);
- }
-
x += 256 + 8;
if (x > Width - 256)
{
@@ -1969,82 +1976,76 @@ void D3DFB::DrawPackedTextures(int packnum)
//
// D3DFB :: AllocPackedTexture
//
-// Finds space to pack an image inside a packing texture and returns it.
+// Finds space to pack an image inside a texture atlas and returns it.
// Large images and those that need to wrap always get their own textures.
//
//==========================================================================
D3DFB::PackedTexture *D3DFB::AllocPackedTexture(int w, int h, bool wrapping, D3DFORMAT format)
{
- PackingTexture *bestpack;
- PackedTexture *bestbox;
- int area;
+ Atlas *pack;
+ Rect box;
+ bool padded;
- // check for 254 to account for padding
- if (w > 254 || h > 254 || wrapping)
- { // Create a new packing texture.
- bestpack = new PackingTexture(this, w, h, format);
- bestpack->OneUse = true;
- bestbox = bestpack->GetBestFit(w, h, area);
- bestbox->Padded = false;
+ // The - 2 to account for padding
+ if (w > 256 - 2 || h > 256 - 2 || wrapping)
+ { // Create a new texture atlas.
+ pack = new Atlas(this, w, h, format);
+ pack->OneUse = true;
+ box = pack->Packer.Insert(w, h);
+ padded = false;
}
else
- { // Try to find space in an existing packing texture.
+ { // Try to find space in an existing texture atlas.
w += 2; // Add padding
h += 2;
- int bestarea = INT_MAX;
- int bestareaever = w * h;
- bestpack = NULL;
- bestbox = NULL;
- for (PackingTexture *pack = Packs; pack != NULL; pack = pack->Next)
+ for (pack = Atlases; pack != NULL; pack = pack->Next)
{
+ // Use the first atlas it fits in.
if (pack->Format == format)
{
- PackedTexture *box = pack->GetBestFit(w, h, area);
- if (area == bestareaever)
- { // An exact fit! Use it!
- bestpack = pack;
- bestbox = box;
- break;
- }
- if (area < bestarea)
+ box = pack->Packer.Insert(w, h);
+ if (box.width != 0)
{
- bestarea = area;
- bestpack = pack;
- bestbox = box;
+ break;
}
}
}
- if (bestpack == NULL)
- { // Create a new packing texture.
- bestpack = new PackingTexture(this, 256, 256, format);
- bestbox = bestpack->GetBestFit(w, h, bestarea);
+ if (pack == NULL)
+ { // Create a new texture atlas.
+ pack = new Atlas(this, DEF_ATLAS_WIDTH, DEF_ATLAS_HEIGHT, format);
+ box = pack->Packer.Insert(w, h);
}
- bestbox->Padded = true;
+ padded = true;
}
- bestpack->AllocateImage(bestbox, w, h);
- return bestbox;
+ assert(box.width != 0 && box.height != 0);
+ return pack->AllocateImage(box, padded);
}
//==========================================================================
//
-// PackingTexture Constructor
+// Atlas Constructor
//
//==========================================================================
-D3DFB::PackingTexture::PackingTexture(D3DFB *fb, int w, int h, D3DFORMAT format)
+D3DFB::Atlas::Atlas(D3DFB *fb, int w, int h, D3DFORMAT format)
+ : Packer(w, h, true)
{
Tex = NULL;
Format = format;
UsedList = NULL;
- EmptyList = NULL;
- FreeList = NULL;
OneUse = false;
Width = 0;
Height = 0;
+ Next = NULL;
- Next = fb->Packs;
- fb->Packs = this;
+ // Attach to the end of the atlas list
+ Atlas **prev = &fb->Atlases;
+ while (*prev != NULL)
+ {
+ prev = &((*prev)->Next);
+ }
+ *prev = this;
#if 1
if (FAILED(fb->D3DDevice->CreateTexture(w, h, 1, 0, format, D3DPOOL_MANAGED, &Tex, NULL)))
@@ -2061,18 +2062,15 @@ D3DFB::PackingTexture::PackingTexture(D3DFB *fb, int w, int h, D3DFORMAT format)
}
Width = w;
Height = h;
-
- // The whole texture is initially empty.
- AddEmptyBox(0, 0, w, h);
}
//==========================================================================
//
-// PackingTexture Destructor
+// Atlas Destructor
//
//==========================================================================
-D3DFB::PackingTexture::~PackingTexture()
+D3DFB::Atlas::~Atlas()
{
PackedTexture *box, *next;
@@ -2082,85 +2080,36 @@ D3DFB::PackingTexture::~PackingTexture()
next = box->Next;
delete box;
}
- for (box = EmptyList; box != NULL; box = next)
- {
- next = box->Next;
- delete box;
- }
- for (box = FreeList; box != NULL; box = next)
- {
- next = box->Next;
- delete box;
- }
}
//==========================================================================
//
-// PackingTexture :: GetBestFit
-//
-// Returns the empty box that provides the best fit for the requested
-// dimensions, or NULL if none of them are large enough.
-//
-//==========================================================================
-
-D3DFB::PackedTexture *D3DFB::PackingTexture::GetBestFit(int w, int h, int &area)
-{
- PackedTexture *box;
- int smallestarea = INT_MAX;
- PackedTexture *smallestbox = NULL;
-
- for (box = EmptyList; box != NULL; box = box->Next)
- {
- int boxw = box->Area.right - box->Area.left;
- int boxh = box->Area.bottom - box->Area.top;
- if (boxw >= w && boxh >= h)
- {
- int boxarea = boxw * boxh;
- if (boxarea < smallestarea)
- {
- smallestarea = boxarea;
- smallestbox = box;
- if (boxw == w && boxh == h)
- { // An exact fit! Use it!
- break;
- }
- }
- }
- }
- area = smallestarea;
- return smallestbox;
-}
-
-//==========================================================================
-//
-// PackingTexture :: AllocateImage
+// Atlas :: AllocateImage
//
// Moves the box from the empty list to the used list, sizing it to the
// requested dimensions and adding additional boxes to the empty list if
// needed.
//
-// The passed box *MUST* be in this packing texture's empty list.
+// The passed box *MUST* be in this texture atlas's empty list.
//
//==========================================================================
-void D3DFB::PackingTexture::AllocateImage(D3DFB::PackedTexture *box, int w, int h)
+D3DFB::PackedTexture *D3DFB::Atlas::AllocateImage(const Rect &rect, bool padded)
{
- RECT start = box->Area;
+ PackedTexture *box = new PackedTexture;
- box->Area.right = box->Area.left + w;
- box->Area.bottom = box->Area.top + h;
+ box->Owner = this;
+ box->Area.left = rect.x;
+ box->Area.top = rect.y;
+ box->Area.right = rect.x + rect.width;
+ box->Area.bottom = rect.y + rect.height;
- box->Left = float(box->Area.left + box->Padded) / Width;
- box->Right = float(box->Area.right - box->Padded) / Width;
- box->Top = float(box->Area.top + box->Padded) / Height;
- box->Bottom = float(box->Area.bottom - box->Padded) / Height;
+ box->Left = float(box->Area.left + padded) / Width;
+ box->Right = float(box->Area.right - padded) / Width;
+ box->Top = float(box->Area.top + padded) / Height;
+ box->Bottom = float(box->Area.bottom - padded) / Height;
- // Remove it from the empty list.
- *(box->Prev) = box->Next;
- if (box->Next != NULL)
- {
- box->Next->Prev = box->Prev;
- }
+ box->Padded = padded;
// Add it to the used list.
box->Next = UsedList;
@@ -2171,158 +2120,36 @@ void D3DFB::PackingTexture::AllocateImage(D3DFB::PackedTexture *box, int w, int
UsedList = box;
box->Prev = &UsedList;
- // If we didn't use the whole box, split the remainder into the empty list.
- if (box->Area.bottom + 7 < start.bottom && box->Area.right + 7 < start.right)
- {
- // Split like this:
- // +---+------+
- // |###| |
- // +---+------+
- // | |
- // | |
- // +----------+
- if (box->Area.bottom < start.bottom)
- {
- AddEmptyBox(start.left, box->Area.bottom, start.right, start.bottom);
- }
- if (box->Area.right < start.right)
- {
- AddEmptyBox(box->Area.right, start.top, start.right, box->Area.bottom);
- }
- }
- else
- {
- // Split like this:
- // +---+------+
- // |###| |
- // +---+ |
- // | | |
- // | | |
- // +---+------+
- if (box->Area.bottom < start.bottom)
- {
- AddEmptyBox(start.left, box->Area.bottom, box->Area.right, start.bottom);
- }
- if (box->Area.right < start.right)
- {
- AddEmptyBox(box->Area.right, start.top, start.right, start.bottom);
- }
- }
-}
-
-//==========================================================================
-//
-// PackingTexture :: AddEmptyBox
-//
-// Adds a box with the specified dimensions to the empty list.
-//
-//==========================================================================
-
-void D3DFB::PackingTexture::AddEmptyBox(int left, int top, int right, int bottom)
-{
- PackedTexture *box = AllocateBox();
- box->Area.left = left;
- box->Area.top = top;
- box->Area.right = right;
- box->Area.bottom = bottom;
- box->Next = EmptyList;
- if (box->Next != NULL)
- {
- box->Next->Prev = &box->Next;
- }
- box->Prev = &EmptyList;
- EmptyList = box;
-}
-
-//==========================================================================
-//
-// PackingTexture :: AllocateBox
-//
-// Returns a new PackedTexture box, either by retrieving one off the free
-// list or by creating a new one. The box is not linked into a list.
-//
-//==========================================================================
-
-D3DFB::PackedTexture *D3DFB::PackingTexture::AllocateBox()
-{
- PackedTexture *box;
-
- if (FreeList != NULL)
- {
- box = FreeList;
- FreeList = box->Next;
- if (box->Next != NULL)
- {
- box->Next->Prev = &FreeList;
- }
- }
- else
- {
- box = new PackedTexture;
- box->Owner = this;
- }
return box;
}
//==========================================================================
//
-// PackingTexture :: FreeBox
+// Atlas :: FreeBox
//
-// Removes a box from its current list and adds it to the empty list,
-// updating EmptyArea. If there are no boxes left in the used list, then
-// the empty list is replaced with a single box, so the texture can be
-// subdivided again.
+// Removes a box from the used list and deletes it. Space is returned to the
+// waste list. Once all boxes for this atlas are freed, the entire bin
+// packer is reinitialized for maximum efficiency.
//
//==========================================================================
-void D3DFB::PackingTexture::FreeBox(D3DFB::PackedTexture *box)
+void D3DFB::Atlas::FreeBox(D3DFB::PackedTexture *box)
{
*(box->Prev) = box->Next;
if (box->Next != NULL)
{
box->Next->Prev = box->Prev;
}
- box->Next = EmptyList;
- box->Prev = &EmptyList;
- if (EmptyList != NULL)
- {
- EmptyList->Prev = &box->Next;
- }
- EmptyList = box;
+ Rect waste;
+ waste.x = box->Area.left;
+ waste.y = box->Area.top;
+ waste.width = box->Area.right - box->Area.left;
+ waste.height = box->Area.bottom - box->Area.top;
+ box->Owner->Packer.AddWaste(waste);
+ delete box;
if (UsedList == NULL)
- { // No more space in use! Move all but this into the free list.
- if (box->Next != NULL)
- {
- D3DFB::PackedTexture *lastbox;
-
- // Find the last box in the free list.
- lastbox = FreeList;
- if (lastbox != NULL)
- {
- while (lastbox->Next != NULL)
- {
- lastbox = lastbox->Next;
- }
- }
- // Chain the empty list to the end of the free list.
- if (lastbox != NULL)
- {
- lastbox->Next = box->Next;
- box->Next->Prev = &lastbox->Next;
- }
- else
- {
- FreeList = box->Next;
- box->Next->Prev = &FreeList;
- }
- box->Next = NULL;
- }
- // Now this is the only box in the empty list, so it should
- // contain the whole texture.
- box->Area.left = 0;
- box->Area.top = 0;
- box->Area.right = Width;
- box->Area.bottom = Height;
+ {
+ Packer.Init(Width, Height, true);
}
}
@@ -2407,6 +2234,7 @@ bool D3DTex::CheckWrapping(bool wrapping)
bool D3DTex::Create(D3DFB *fb, bool wrapping)
{
+ assert(Box == NULL);
if (Box != NULL)
{
Box->Owner->FreeBox(Box);
@@ -3436,6 +3264,22 @@ void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR
IndexPos += 6;
}
+//==========================================================================
+//
+// D3DFB :: AddColorOnlyRect
+//
+// Like AddColorOnlyQuad, except it's hollow.
+//
+//==========================================================================
+
+void D3DFB::AddColorOnlyRect(int left, int top, int width, int height, D3DCOLOR color)
+{
+ AddColorOnlyQuad(left, top, width - 1, 1, color); // top
+ AddColorOnlyQuad(left + width - 1, top, 1, height - 1, color); // right
+ AddColorOnlyQuad(left + 1, top + height - 1, width - 1, 1, color); // bottom
+ AddColorOnlyQuad(left, top + 1, 1, height - 1, color); // left
+}
+
//==========================================================================
//
// D3DFB :: CheckQuadBatch
@@ -4004,7 +3848,7 @@ void D3DFB::SetPaletteTexture(IDirect3DTexture9 *texture, int count, D3DCOLOR bo
SetTexture(1, texture);
}
-void D3DFB::SetPalTexBilinearConstants(PackingTexture *tex)
+void D3DFB::SetPalTexBilinearConstants(Atlas *tex)
{
#if 0
float con[8];
diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h
index 934931ea01..8b0c88f45a 100644
--- a/src/win32/win32iface.h
+++ b/src/win32/win32iface.h
@@ -279,7 +279,7 @@ private:
friend class D3DPal;
struct PackedTexture;
- struct PackingTexture;
+ struct Atlas;
struct FBVERTEX
{
@@ -375,6 +375,7 @@ private:
static void SetColorOverlay(DWORD color, float alpha, D3DCOLOR &color0, D3DCOLOR &color1);
void DoWindowedGamma();
void AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR color);
+ void AddColorOnlyRect(int left, int top, int width, int height, D3DCOLOR color);
void CheckQuadBatch(int numtris=2, int numverts=4);
void BeginQuadBatch();
void EndQuadBatch();
@@ -392,7 +393,7 @@ private:
void SetPixelShader(IDirect3DPixelShader9 *shader);
void SetTexture(int tnum, IDirect3DTexture9 *texture);
void SetPaletteTexture(IDirect3DTexture9 *texture, int count, D3DCOLOR border_color);
- void SetPalTexBilinearConstants(PackingTexture *texture);
+ void SetPalTexBilinearConstants(Atlas *texture);
BOOL AlphaTestEnabled;
BOOL AlphaBlendEnabled;
@@ -431,7 +432,7 @@ private:
BYTE BlockNum;
D3DPal *Palettes;
D3DTex *Textures;
- PackingTexture *Packs;
+ Atlas *Atlases;
HRESULT LastHR;
UINT Adapter;
diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt
index 1bd031ed8e..13f0d22a70 100644
--- a/wadsrc/static/compatibility.txt
+++ b/wadsrc/static/compatibility.txt
@@ -403,6 +403,7 @@ D0139194F7817BF06F3988DFC47DB38D // Whispers of Satan map29
}
D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9
+19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update
{
pointonline
}
diff --git a/wadsrc/static/filter/doom.freedoom/decaldef.z b/wadsrc/static/filter/doom.freedoom/decaldef.z
new file mode 100644
index 0000000000..68b85a8485
--- /dev/null
+++ b/wadsrc/static/filter/doom.freedoom/decaldef.z
@@ -0,0 +1,29 @@
+
+/***** BFG Scorches ********************************************************/
+
+decal BFGLightning1
+{
+ pic BFGLITE1
+ shade "80 80 ff"
+ fullbright
+ randomflipx
+ animator GoAway2
+ lowerdecal BFGScorch
+}
+
+decal BFGLightning2
+{
+ pic BFGLITE2
+ shade "80 80 ff"
+ fullbright
+ randomflipy
+ animator GoAway2
+ lowerdecal BFGScorch
+}
+
+decalgroup BFGLightning
+{
+ BFGLightning1 1
+ BFGLightning2 1
+}
+
diff --git a/wadsrc/static/iwadinfo.txt b/wadsrc/static/iwadinfo.txt
index 6c958ddfa2..401f3ca4c0 100644
--- a/wadsrc/static/iwadinfo.txt
+++ b/wadsrc/static/iwadinfo.txt
@@ -370,6 +370,7 @@ Names
"doom.wad"
"doom1.wad"
"heretic.wad"
+ "hereticsr.wad"
"heretic1.wad"
"hexen.wad"
"hexdd.wad"
diff --git a/wadsrc/static/mapinfo/common.txt b/wadsrc/static/mapinfo/common.txt
index f26ca67315..4b663047ce 100644
--- a/wadsrc/static/mapinfo/common.txt
+++ b/wadsrc/static/mapinfo/common.txt
@@ -118,70 +118,70 @@ DoomEdNums
9997 = SecActExit
9998 = SecActEnter
9999 = SecActHitFloor
- 14001 = AmbientSound, 1
- 14002 = AmbientSound, 2
- 14003 = AmbientSound, 3
- 14004 = AmbientSound, 4
- 14005 = AmbientSound, 5
- 14006 = AmbientSound, 6
- 14007 = AmbientSound, 7
- 14008 = AmbientSound, 8
- 14009 = AmbientSound, 9
- 14010 = AmbientSound, 10
- 14011 = AmbientSound, 11
- 14012 = AmbientSound, 12
- 14013 = AmbientSound, 13
- 14014 = AmbientSound, 14
- 14015 = AmbientSound, 15
- 14016 = AmbientSound, 16
- 14017 = AmbientSound, 17
- 14018 = AmbientSound, 18
- 14019 = AmbientSound, 19
- 14020 = AmbientSound, 20
- 14021 = AmbientSound, 21
- 14022 = AmbientSound, 22
- 14023 = AmbientSound, 23
- 14024 = AmbientSound, 24
- 14025 = AmbientSound, 25
- 14026 = AmbientSound, 26
- 14027 = AmbientSound, 27
- 14028 = AmbientSound, 28
- 14029 = AmbientSound, 29
- 14030 = AmbientSound, 30
- 14031 = AmbientSound, 31
- 14032 = AmbientSound, 32
- 14033 = AmbientSound, 33
- 14034 = AmbientSound, 34
- 14035 = AmbientSound, 35
- 14036 = AmbientSound, 36
- 14037 = AmbientSound, 37
- 14038 = AmbientSound, 38
- 14039 = AmbientSound, 39
- 14040 = AmbientSound, 40
- 14041 = AmbientSound, 41
- 14042 = AmbientSound, 42
- 14043 = AmbientSound, 43
- 14044 = AmbientSound, 44
- 14045 = AmbientSound, 45
- 14046 = AmbientSound, 46
- 14047 = AmbientSound, 47
- 14048 = AmbientSound, 48
- 14049 = AmbientSound, 49
- 14050 = AmbientSound, 50
- 14051 = AmbientSound, 51
- 14052 = AmbientSound, 52
- 14053 = AmbientSound, 53
- 14054 = AmbientSound, 54
- 14055 = AmbientSound, 55
- 14056 = AmbientSound, 56
- 14057 = AmbientSound, 57
- 14058 = AmbientSound, 58
- 14059 = AmbientSound, 59
- 14060 = AmbientSound, 60
- 14061 = AmbientSound, 61
- 14062 = AmbientSound, 62
- 14063 = AmbientSound, 63
- 14064 = AmbientSound, 64
+ 14001 = AmbientSound, 1, +
+ 14002 = AmbientSound, 2, +
+ 14003 = AmbientSound, 3, +
+ 14004 = AmbientSound, 4, +
+ 14005 = AmbientSound, 5, +
+ 14006 = AmbientSound, 6, +
+ 14007 = AmbientSound, 7, +
+ 14008 = AmbientSound, 8, +
+ 14009 = AmbientSound, 9, +
+ 14010 = AmbientSound, 10, +
+ 14011 = AmbientSound, 11, +
+ 14012 = AmbientSound, 12, +
+ 14013 = AmbientSound, 13, +
+ 14014 = AmbientSound, 14, +
+ 14015 = AmbientSound, 15, +
+ 14016 = AmbientSound, 16, +
+ 14017 = AmbientSound, 17, +
+ 14018 = AmbientSound, 18, +
+ 14019 = AmbientSound, 19, +
+ 14020 = AmbientSound, 20, +
+ 14021 = AmbientSound, 21, +
+ 14022 = AmbientSound, 22, +
+ 14023 = AmbientSound, 23, +
+ 14024 = AmbientSound, 24, +
+ 14025 = AmbientSound, 25, +
+ 14026 = AmbientSound, 26, +
+ 14027 = AmbientSound, 27, +
+ 14028 = AmbientSound, 28, +
+ 14029 = AmbientSound, 29, +
+ 14030 = AmbientSound, 30, +
+ 14031 = AmbientSound, 31, +
+ 14032 = AmbientSound, 32, +
+ 14033 = AmbientSound, 33, +
+ 14034 = AmbientSound, 34, +
+ 14035 = AmbientSound, 35, +
+ 14036 = AmbientSound, 36, +
+ 14037 = AmbientSound, 37, +
+ 14038 = AmbientSound, 38, +
+ 14039 = AmbientSound, 39, +
+ 14040 = AmbientSound, 40, +
+ 14041 = AmbientSound, 41, +
+ 14042 = AmbientSound, 42, +
+ 14043 = AmbientSound, 43, +
+ 14044 = AmbientSound, 44, +
+ 14045 = AmbientSound, 45, +
+ 14046 = AmbientSound, 46, +
+ 14047 = AmbientSound, 47, +
+ 14048 = AmbientSound, 48, +
+ 14049 = AmbientSound, 49, +
+ 14050 = AmbientSound, 50, +
+ 14051 = AmbientSound, 51, +
+ 14052 = AmbientSound, 52, +
+ 14053 = AmbientSound, 53, +
+ 14054 = AmbientSound, 54, +
+ 14055 = AmbientSound, 55, +
+ 14056 = AmbientSound, 56, +
+ 14057 = AmbientSound, 57, +
+ 14058 = AmbientSound, 58, +
+ 14059 = AmbientSound, 59, +
+ 14060 = AmbientSound, 60, +
+ 14061 = AmbientSound, 61, +
+ 14062 = AmbientSound, 62, +
+ 14063 = AmbientSound, 63, +
+ 14064 = AmbientSound, 64, +
14065 = AmbientSound
14066 = SoundSequence
14067 = AmbientSoundNoGravity
diff --git a/wadsrc/static/mapinfo/doom2bfg.txt b/wadsrc/static/mapinfo/doom2bfg.txt
index cc82c4e191..28bea129d7 100644
--- a/wadsrc/static/mapinfo/doom2bfg.txt
+++ b/wadsrc/static/mapinfo/doom2bfg.txt
@@ -3,7 +3,7 @@ include "mapinfo/doom2.txt"
gameinfo
{
- titlepage = "INTERPIC"
+ titlepage = "DMENUPIC"
}
clearepisodes
diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt
index 087c067d14..add8444557 100644
--- a/wadsrc/static/menudef.txt
+++ b/wadsrc/static/menudef.txt
@@ -448,6 +448,7 @@ OptionMenu "CustomizeControls"
Control "Strafe right", "+moveright"
Control "Turn left", "+left"
Control "Turn right", "+right"
+ Control "Quick Turn", "turn180"
Control "Jump", "+jump"
Control "Crouch", "+crouch"
Control "Crouch Toggle", "crouch"
diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt
index ad270beb45..7b4367ee33 100644
--- a/wadsrc/static/xlat/eternity.txt
+++ b/wadsrc/static/xlat/eternity.txt
@@ -170,7 +170,7 @@ define Unsupported (0)
384 = 0, Static_Init(0, 3, 0, 10) // "Attach_MirrorCeilingToControl"
// Attach tagged portal to front sector
-385 = 0, Sector_SetPortal(0, 1, 2, tag) // "Apply_PortalToFrontsector"
+385 = 0, Sector_SetPortal(0, 1, 3, tag) // "Apply_PortalToFrontsector"
// Slopes!
386 = 0, Plane_Align (1, 0) // "Slope_FrontsectorFloor"
diff --git a/zdoom.vcproj b/zdoom.vcproj
index 58ce369cba..e000f153df 100644
--- a/zdoom.vcproj
+++ b/zdoom.vcproj
@@ -666,6 +666,10 @@
RelativePath=".\src\gitinfo.cpp"
>
+
+
@@ -1026,6 +1030,10 @@
RelativePath=".\src\skins.cpp"
>
+
+
@@ -1311,6 +1319,10 @@
RelativePath=".\src\gstrings.h"
>
+
+
@@ -1491,6 +1503,10 @@
RelativePath=".\src\po_man.h"
>
+
+
@@ -1515,6 +1531,10 @@
RelativePath=".\src\skins.h"
>
+
+