// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include "include/cef_stream.h"
#include "include/cef_zip_reader.h"
#include "include/wrapper/cef_zip_archive.h"
#include "tests/gtest/include/gtest/gtest.h"

namespace {

unsigned char g_test_zip[] = {
    0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x7f,
    0x57, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61,
    0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x50, 0x4b, 0x03, 0x04, 0x0a,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x7f, 0x57, 0x3d, 0xf8, 0x47, 0x0c,
    0xc6, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00,
    0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76,
    0x65, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x2e, 0x74, 0x78, 0x74,
    0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20,
    0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x2e, 0x50, 0x4b, 0x03, 0x04, 0x0a,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x7f, 0x57, 0x3d, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00,
    0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76,
    0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x2f, 0x50,
    0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x7f, 0x57,
    0x3d, 0x43, 0xe3, 0x11, 0x5f, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
    0x00, 0x21, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72,
    0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72,
    0x20, 0x31, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x61, 0x2e, 0x74,
    0x78, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f,
    0x66, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x41, 0x2e, 0x50, 0x4b,
    0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x7f, 0x57, 0x3d,
    0x80, 0xb0, 0x3c, 0x74, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
    0x21, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63,
    0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20,
    0x31, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x62, 0x2e, 0x74, 0x78,
    0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66,
    0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x42, 0x2e, 0x50, 0x4b, 0x03,
    0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x7f, 0x57, 0x3d, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
    0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68,
    0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31,
    0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x61, 0x2f, 0x50,
    0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7f, 0x57,
    0x3d, 0x15, 0xed, 0x04, 0x2c, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00,
    0x00, 0x2c, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72,
    0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72,
    0x20, 0x31, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x61,
    0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x61, 0x31, 0x2e, 0x74, 0x78,
    0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66,
    0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x41, 0x31, 0x2e, 0x50, 0x4b,
    0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x7f, 0x57, 0x3d,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x16, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63,
    0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20,
    0x32, 0x2f, 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x02, 0x80, 0x57, 0x3d, 0x1a, 0x5d, 0x57, 0x5d, 0x14, 0x00, 0x00, 0x00,
    0x14, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74,
    0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c,
    0x64, 0x65, 0x72, 0x20, 0x32, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x32,
    0x61, 0x2e, 0x74, 0x78, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
    0x73, 0x20, 0x6f, 0x66, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x32, 0x41,
    0x2e, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x67, 0x7f, 0x57, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74,
    0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f,
    0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x70, 0x7f, 0x57, 0x3d, 0xf8, 0x47, 0x0c, 0xc6, 0x13, 0x00, 0x00, 0x00,
    0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x74, 0x65,
    0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66,
    0x69, 0x6c, 0x65, 0x20, 0x31, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b, 0x01,
    0x02, 0x14, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x7f, 0x57,
    0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
    0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f,
    0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64,
    0x65, 0x72, 0x20, 0x31, 0x2f, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x7f, 0x57, 0x3d, 0x43, 0xe3, 0x11,
    0x5f, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xa7,
    0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68,
    0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31,
    0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x61, 0x2e, 0x74, 0x78, 0x74,
    0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x78, 0x7f, 0x57, 0x3d, 0x80, 0xb0, 0x3c, 0x74, 0x14, 0x00, 0x00, 0x00,
    0x14, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x74, 0x65,
    0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66,
    0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x2f, 0x66, 0x69, 0x6c, 0x65,
    0x20, 0x31, 0x62, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b, 0x01, 0x02, 0x14,
    0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x7f, 0x57, 0x3d, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
    0x00, 0x4d, 0x01, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72,
    0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72,
    0x20, 0x31, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x61,
    0x2f, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x7c, 0x7f, 0x57, 0x3d, 0x15, 0xed, 0x04, 0x2c, 0x15, 0x00, 0x00,
    0x00, 0x15, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x8b, 0x01, 0x00, 0x00, 0x74,
    0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f,
    0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x2f, 0x66, 0x6f, 0x6c,
    0x64, 0x65, 0x72, 0x20, 0x31, 0x61, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20,
    0x31, 0x61, 0x31, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b, 0x01, 0x02, 0x14,
    0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x7f, 0x57, 0x3d, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
    0x00, 0xea, 0x01, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72,
    0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72,
    0x20, 0x32, 0x2f, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x02, 0x80, 0x57, 0x3d, 0x1a, 0x5d, 0x57, 0x5d, 0x14,
    0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x00,
    0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76,
    0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x32, 0x2f, 0x66,
    0x69, 0x6c, 0x65, 0x20, 0x32, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b,
    0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x09, 0x00, 0x9d, 0x02,
    0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};

}  // namespace

// Test Zip reading.
TEST(ZipReaderTest, Read) {
  // Create the stream reader.
  CefRefPtr<CefStreamReader> stream(
      CefStreamReader::CreateForData(g_test_zip, sizeof(g_test_zip) - 1));
  ASSERT_TRUE(stream.get() != nullptr);

  // Create the Zip reader.
  CefRefPtr<CefZipReader> reader(CefZipReader::Create(stream));
  ASSERT_TRUE(reader.get() != nullptr);

  char buff[25];

  // Walk through the archive contents.
  ASSERT_TRUE(reader->MoveToFirstFile());
  ASSERT_EQ(reader->GetFileName(), "test_archive/");
  ASSERT_EQ(reader->GetFileSize(), 0);

  ASSERT_TRUE(reader->MoveToNextFile());
  ASSERT_EQ(reader->GetFileName(), "test_archive/file 1.txt");
  ASSERT_EQ(reader->GetFileSize(), 19);
  ASSERT_TRUE(reader->OpenFile(""));
  ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 19);
  ASSERT_TRUE(!strncmp(buff, "Contents of file 1.", 19));

  ASSERT_TRUE(reader->MoveToNextFile());
  ASSERT_EQ(reader->GetFileName(), "test_archive/folder 1/");
  ASSERT_EQ(reader->GetFileSize(), 0);

  ASSERT_TRUE(reader->MoveToNextFile());
  ASSERT_EQ(reader->GetFileName(), "test_archive/folder 1/file 1a.txt");
  ASSERT_EQ(reader->GetFileSize(), 20);
  ASSERT_TRUE(reader->OpenFile(""));
  ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 20);
  ASSERT_TRUE(reader->CloseFile());
  ASSERT_TRUE(!strncmp(buff, "Contents of file 1A.", 20));

  ASSERT_TRUE(reader->MoveToNextFile());
  ASSERT_EQ(reader->GetFileName(), "test_archive/folder 1/file 1b.txt");
  ASSERT_EQ(reader->GetFileSize(), 20);
  ASSERT_TRUE(reader->OpenFile(""));
  ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 20);
  ASSERT_TRUE(reader->CloseFile());
  ASSERT_TRUE(!strncmp(buff, "Contents of file 1B.", 20));

  ASSERT_TRUE(reader->MoveToNextFile());
  ASSERT_EQ(reader->GetFileName(), "test_archive/folder 1/folder 1a/");
  ASSERT_EQ(reader->GetFileSize(), 0);

  ASSERT_TRUE(reader->MoveToNextFile());
  ASSERT_EQ(reader->GetFileName(),
            "test_archive/folder 1/folder 1a/file 1a1.txt");
  ASSERT_EQ(reader->GetFileSize(), 21);
  ASSERT_TRUE(reader->OpenFile(""));
  ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 21);
  ASSERT_TRUE(reader->CloseFile());
  ASSERT_TRUE(!strncmp(buff, "Contents of file 1A1.", 21));

  ASSERT_TRUE(reader->MoveToNextFile());
  ASSERT_EQ(reader->GetFileName(), "test_archive/folder 2/");
  ASSERT_EQ(reader->GetFileSize(), 0);

  ASSERT_TRUE(reader->MoveToNextFile());
  ASSERT_EQ(reader->GetFileName(), "test_archive/folder 2/file 2a.txt");
  ASSERT_EQ(reader->GetFileSize(), 20);
  ASSERT_TRUE(reader->OpenFile(""));
  ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 20);
  ASSERT_TRUE(reader->CloseFile());
  ASSERT_TRUE(!strncmp(buff, "Contents of file 2A.", 20));

  ASSERT_FALSE(reader->MoveToNextFile());

  // Try seeking a particular file
  ASSERT_TRUE(reader->MoveToFile("TEST_ARCHIVE/FOLDER 1/FILE 1B.TXT", false));
  ASSERT_EQ(reader->GetFileName(), "test_archive/folder 1/file 1b.txt");
  ASSERT_EQ(reader->GetFileSize(), 20);
  ASSERT_TRUE(reader->OpenFile(""));
  ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 20);
  ASSERT_TRUE(reader->CloseFile());
  ASSERT_TRUE(!strncmp(buff, "Contents of file 1B.", 20));

  ASSERT_TRUE(reader->MoveToFile("test_archive/folder 1/file 1b.txt", true));
  ASSERT_FALSE(reader->MoveToFile("test_archive/folder 1/FILE 1B.txt", true));

  ASSERT_TRUE(reader->Close());
}

// Test CefZipArchive object.
TEST(ZipReaderTest, ReadArchive) {
  // Create the stream reader.
  CefRefPtr<CefStreamReader> stream(
      CefStreamReader::CreateForData(g_test_zip, sizeof(g_test_zip) - 1));
  ASSERT_TRUE(stream.get() != nullptr);

  // Create the Zip archive object.
  CefRefPtr<CefZipArchive> archive(new CefZipArchive());

  ASSERT_EQ(archive->Load(stream, CefString(), false), (size_t)5);

  ASSERT_TRUE(archive->HasFile("test_archive/file 1.txt"));
  ASSERT_TRUE(archive->HasFile("test_archive/folder 1/file 1a.txt"));
  ASSERT_TRUE(archive->HasFile("test_archive/FOLDER 1/file 1b.txt"));
  ASSERT_TRUE(archive->HasFile("test_archive/folder 1/folder 1a/file 1a1.txt"));
  ASSERT_TRUE(archive->HasFile("test_archive/folder 2/file 2a.txt"));

  // Test content retrieval.
  CefRefPtr<CefZipArchive::File> file;
  file = archive->GetFile("test_archive/folder 2/file 2a.txt");
  ASSERT_TRUE(file.get());

  ASSERT_EQ(file->GetDataSize(), (size_t)20);
  ASSERT_TRUE(!strncmp(reinterpret_cast<const char*>(file->GetData()),
                       "Contents of file 2A.", 20));

  // Test stream reading.
  CefRefPtr<CefStreamReader> reader(file->GetStreamReader());
  ASSERT_TRUE(reader.get());

  char buff[8];
  ASSERT_EQ(reader->Read(buff, 1, 8), (size_t)8);
  ASSERT_TRUE(!strncmp(buff, "Contents", 8));
  ASSERT_EQ(reader->Read(buff, 1, 8), (size_t)8);
  ASSERT_TRUE(!strncmp(buff, " of file", 8));
  ASSERT_EQ(reader->Read(buff, 1, 8), (size_t)4);
  ASSERT_TRUE(!strncmp(buff, " 2A.", 4));
  ASSERT_TRUE(reader->Eof());
}