summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/unix/CPP/7zip/Archive/Common/FindSignature.cpp
blob: 15aa6ceae7a05a63ed280b9aad56137a9c086791 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// FindSignature.cpp

#include "StdAfx.h"

#include "Common/Buffer.h"

#include "FindSignature.h"

#include "../../Common/StreamUtils.h"

HRESULT FindSignatureInStream(ISequentialInStream *stream,
    const Byte *signature, unsigned signatureSize,
    const UInt64 *limit, UInt64 &resPos)
{
  resPos = 0;
  CByteBuffer byteBuffer2;
  byteBuffer2.SetCapacity(signatureSize);
  RINOK(ReadStream_FALSE(stream, byteBuffer2, signatureSize));

  if (memcmp(byteBuffer2, signature, signatureSize) == 0)
    return S_OK;

  const UInt32 kBufferSize = (1 << 16);
  CByteBuffer byteBuffer;
  byteBuffer.SetCapacity(kBufferSize);
  Byte *buffer = byteBuffer;
  UInt32 numPrevBytes = signatureSize - 1;
  memcpy(buffer, (const Byte *)byteBuffer2 + 1, numPrevBytes);
  resPos = 1;
  for (;;)
  {
    if (limit != NULL)
      if (resPos > *limit)
        return S_FALSE;
    do
    {
      UInt32 numReadBytes = kBufferSize - numPrevBytes;
      UInt32 processedSize;
      RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
      numPrevBytes += processedSize;
      if (processedSize == 0)
        return S_FALSE;
    }
    while (numPrevBytes < signatureSize);
    UInt32 numTests = numPrevBytes - signatureSize + 1;
    for (UInt32 pos = 0; pos < numTests; pos++)
    {
      Byte b = signature[0];
      for (; buffer[pos] != b && pos < numTests; pos++);
      if (pos == numTests)
        break;
      if (memcmp(buffer + pos, signature, signatureSize) == 0)
      {
        resPos += pos;
        return S_OK;
      }
    }
    resPos += numTests;
    numPrevBytes -= numTests;
    memmove(buffer, buffer + numTests, numPrevBytes);
  }
}