| // 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; |
| } |