chromium/tools/mac/icons/additional_tools/makeicns.cc

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <string>

#define arraysize(x) (sizeof(x) / sizeof(x[0]))

namespace {

struct IconType {
  uint32_t magic;
  const char* filename;
};

// clang-format off
const IconType icon_types[] = {
  { 'is32', nullptr },
  { 's8mk', nullptr },
  { 'il32', nullptr },
  { 'l8mk', nullptr },
  { 'ih32', nullptr },
  { 'h8mk', nullptr },
  { 'it32', nullptr },
  { 't8mk', nullptr },

  { 'icp4', "16x16" },
  { 'icp5', "32x32" },
  { 'icp6', "64x64" },
  { 'ic07', "128x128" },
  { 'ic08', "256x256" },
  { 'ic09', "512x512" },
  { 'ic10', "512x512@2x" },  // previously 1024x1024
  { 'ic11', "16x16@2x" },
  { 'ic12', "32x32@2x" },
  { 'ic13', "128x128@2x" },
  { 'ic14', "256x256@2x" },
};
// clang-format on

struct IcnsHeader {
  uint32_t magic;
  uint32_t length;
};

struct IconHeader {
  uint32_t magic;
  uint32_t length;
};

}  // namespace

int main(int argc, char* argv[]) {
  const char* me = argv[0];

  if (argc != 3) {
    fprintf(stderr, "usage: %s <iconset> <icns>\n", me);
    return EXIT_FAILURE;
  }

  const char* output_path = argv[2];
  int output_fd = open(output_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
  if (output_fd < 0) {
    fprintf(stderr, "%s: open %s: %s\n", me, output_path, strerror(errno));
    return EXIT_FAILURE;
  }

  IcnsHeader icns_header = {};
  if (write(output_fd, &icns_header, sizeof(icns_header)) < 0) {
    fprintf(stderr, "%s: write: %s\n", me, strerror(errno));
    return EXIT_FAILURE;
  }
  icns_header.length += sizeof(icns_header);

  for (size_t icon_type_index = 0; icon_type_index < arraysize(icon_types);
       ++icon_type_index) {
    const IconType& icon_type = icon_types[icon_type_index];
    std::string input_path = std::string(argv[1]) + "/";
    if (icon_type.filename) {
      input_path += std::string("icon_") + icon_type.filename + ".png";
    } else {
      char filename[5];
      snprintf(filename, sizeof(filename), "%c%c%c%c", icon_type.magic >> 24,
               (icon_type.magic >> 16) & 0xff, (icon_type.magic >> 8) & 0xff,
               icon_type.magic & 0xff);
      input_path += filename;
    }
    int input_fd = open(input_path.c_str(), O_RDONLY);
    if (input_fd < 0) {
      if (errno == ENOENT) {
        continue;
      }
      fprintf(stderr, "%s: open %s: %s\n", me, input_path.c_str(),
              strerror(errno));
      return EXIT_FAILURE;
    }

    off_t icon_header_offset = lseek(output_fd, 0, SEEK_CUR);
    if (icon_header_offset < 0) {
      fprintf(stderr, "%s: lseek: %s\n", me, strerror(errno));
      return EXIT_FAILURE;
    }

    IconHeader icon_header = {};
    if (write(output_fd, &icon_header, sizeof(icon_header)) < 0) {
      fprintf(stderr, "%s: write: %s\n", me, strerror(errno));
      return EXIT_FAILURE;
    }
    icon_header.length = sizeof(icon_header);
    icns_header.length += icon_header.length;

    ssize_t input_read;
    char buf[4096];
    while ((input_read = read(input_fd, buf, sizeof(buf))) > 0) {
      icon_header.length += input_read;
      if (write(output_fd, buf, input_read) < 0) {
        fprintf(stderr, "%s: write: %s\n", me, strerror(errno));
        return EXIT_FAILURE;
      }
      icns_header.length += input_read;
    }
    if (input_read < 0) {
      fprintf(stderr, "%s: read %s: %s\n", me, input_path.c_str(),
              strerror(errno));
      return EXIT_FAILURE;
    }

    if (close(input_fd) < 0) {
      fprintf(stderr, "%s: close %s: %s\n", me, input_path.c_str(),
              strerror(errno));
      return EXIT_FAILURE;
    }

    off_t end_offset = lseek(output_fd, 0, SEEK_CUR);
    if (end_offset < 0) {
      fprintf(stderr, "%s: lseek: %s\n", me, strerror(errno));
      return EXIT_FAILURE;
    }

    if (lseek(output_fd, icon_header_offset, SEEK_SET) < 0) {
      fprintf(stderr, "%s: lseek: %s\n", me, strerror(errno));
      return EXIT_FAILURE;
    }

    icon_header.magic = htonl(icon_type.magic);
    icon_header.length = htonl(icon_header.length);
    if (write(output_fd, &icon_header, sizeof(icon_header)) < 0) {
      fprintf(stderr, "%s: write: %s\n", me, strerror(errno));
      return EXIT_FAILURE;
    }

    if (lseek(output_fd, end_offset, SEEK_SET) < 0) {
      fprintf(stderr, "%s: lseek: %s\n", me, strerror(errno));
      return EXIT_FAILURE;
    }
  }

  if (lseek(output_fd, 0, SEEK_SET) < 0) {
    fprintf(stderr, "%s: lseek: %s\n", me, strerror(errno));
    return EXIT_FAILURE;
  }

  icns_header.magic = htonl('icns');
  icns_header.length = htonl(icns_header.length);

  if (write(output_fd, &icns_header, sizeof(icns_header)) < 0) {
    fprintf(stderr, "%s: write: %s\n", me, strerror(errno));
    return EXIT_FAILURE;
  }

  if (close(output_fd) < 0) {
    fprintf(stderr, "%s: close %s: %s\n", me, output_path, strerror(errno));
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}