/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "io/ZipArchive.h"

#include "utils/FileMap.h"
#include "ziparchive/zip_archive.h"

#include "Source.h"
#include "util/Util.h"

using ::android::StringPiece;

namespace aapt {
namespace io {

ZipFile::ZipFile(ZipArchiveHandle handle, const ZipEntry& entry,
                 const Source& source)
    : zip_handle_(handle), zip_entry_(entry), source_(source) {}

std::unique_ptr<IData> ZipFile::OpenAsData() {
  if (zip_entry_.method == kCompressStored) {
    int fd = GetFileDescriptor(zip_handle_);

    android::FileMap file_map;
    bool result = file_map.create(nullptr, fd, zip_entry_.offset,
                                  zip_entry_.uncompressed_length, true);
    if (!result) {
      return {};
    }
    return util::make_unique<MmappedData>(std::move(file_map));

  } else {
    std::unique_ptr<uint8_t[]> data =
        std::unique_ptr<uint8_t[]>(new uint8_t[zip_entry_.uncompressed_length]);
    int32_t result =
        ExtractToMemory(zip_handle_, &zip_entry_, data.get(),
                        static_cast<uint32_t>(zip_entry_.uncompressed_length));
    if (result != 0) {
      return {};
    }
    return util::make_unique<MallocData>(std::move(data),
                                         zip_entry_.uncompressed_length);
  }
}

std::unique_ptr<io::InputStream> ZipFile::OpenInputStream() {
  return OpenAsData();
}

const Source& ZipFile::GetSource() const {
  return source_;
}

bool ZipFile::WasCompressed() {
  return zip_entry_.method != kCompressStored;
}

ZipFileCollectionIterator::ZipFileCollectionIterator(
    ZipFileCollection* collection)
    : current_(collection->files_.begin()), end_(collection->files_.end()) {}

bool ZipFileCollectionIterator::HasNext() {
  return current_ != end_;
}

IFile* ZipFileCollectionIterator::Next() {
  IFile* result = current_->get();
  ++current_;
  return result;
}

ZipFileCollection::ZipFileCollection() : handle_(nullptr) {}

std::unique_ptr<ZipFileCollection> ZipFileCollection::Create(
    const StringPiece& path, std::string* out_error) {
  constexpr static const int32_t kEmptyArchive = -6;

  std::unique_ptr<ZipFileCollection> collection =
      std::unique_ptr<ZipFileCollection>(new ZipFileCollection());

  int32_t result = OpenArchive(path.data(), &collection->handle_);
  if (result != 0) {
    // If a zip is empty, result will be an error code. This is fine and we
    // should
    // return an empty ZipFileCollection.
    if (result == kEmptyArchive) {
      return collection;
    }

    if (out_error) *out_error = ErrorCodeString(result);
    return {};
  }

  void* cookie = nullptr;
  result = StartIteration(collection->handle_, &cookie);
  if (result != 0) {
    if (out_error) *out_error = ErrorCodeString(result);
    return {};
  }

  using IterationEnder = std::unique_ptr<void, decltype(EndIteration)*>;
  IterationEnder iteration_ender(cookie, EndIteration);

  ZipString zip_entry_name;
  ZipEntry zip_data;
  while ((result = Next(cookie, &zip_data, &zip_entry_name)) == 0) {
    std::string zip_entry_path =
        std::string(reinterpret_cast<const char*>(zip_entry_name.name),
                    zip_entry_name.name_length);
    std::string nested_path = path.to_string() + "@" + zip_entry_path;
    std::unique_ptr<IFile> file =
        util::make_unique<ZipFile>(collection->handle_, zip_data, Source(nested_path));
    collection->files_by_name_[zip_entry_path] = file.get();
    collection->files_.push_back(std::move(file));
  }

  if (result != -1) {
    if (out_error) *out_error = ErrorCodeString(result);
    return {};
  }
  return collection;
}

IFile* ZipFileCollection::FindFile(const StringPiece& path) {
  auto iter = files_by_name_.find(path.to_string());
  if (iter != files_by_name_.end()) {
    return iter->second;
  }
  return nullptr;
}

std::unique_ptr<IFileCollectionIterator> ZipFileCollection::Iterator() {
  return util::make_unique<ZipFileCollectionIterator>(this);
}

ZipFileCollection::~ZipFileCollection() {
  if (handle_) {
    CloseArchive(handle_);
  }
}

}  // namespace io
}  // namespace aapt
