chromium/tools/mac/icons/additional_tools/unpackicon.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.

// http://www.macdisk.com/maciconen.php#RLE
// The algorithm is PackBits or PackBits-like.
// Produces a raw RGB image.
// Use with ih32, il32, is32, it32. For it32, use "skip", because there are four
// bytes of unknown use (typically zero) before the compressed data begins.

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

#include <string>

#include "unpackicon.h"

bool UnpackIcon(const char* input_path, const char* output_path, bool skip) {
  int input_fd = open(input_path, O_RDONLY);
  if (input_fd < 0) {
    fprintf(stderr, "open %s: %s\n", input_path, strerror(errno));
    return false;
  }

  if (skip) {
    uint32_t skip_buf;
    ssize_t read_skip_rv = read(input_fd, &skip_buf, sizeof(skip_buf));
    if (read_skip_rv < 0) {
      fprintf(stderr, "read %s: %s\n", input_path, strerror(errno));
      return false;
    } else if (read_skip_rv != sizeof(skip_buf)) {
      fprintf(stderr, "read %s: expected %zu, observed %zd\n", input_path,
              sizeof(skip_buf), read_skip_rv);
      return false;
    }
  }

  int output_fd = open(output_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
  if (output_fd < 0) {
    fprintf(stderr, "open %s: %s\n", output_path, strerror(errno));
    return false;
  }

  ssize_t read_cmd_rv;
  do {
    uint8_t cmd;
    read_cmd_rv = read(input_fd, &cmd, 1);
    if (read_cmd_rv < 0) {
      fprintf(stderr, "read %s: %s\n", input_path, strerror(errno));
      return false;
    } else if (read_cmd_rv == 0) {
      break;
    }

    if ((cmd & 0x80) == 0) {
      const size_t count = cmd + 1;
      char buf[128];
      ssize_t read_buf_rv = read(input_fd, buf, count);
      if (read_buf_rv < 0) {
        fprintf(stderr, "read %s: %s\n", input_path, strerror(errno));
        return false;
      } else if (read_buf_rv != count) {
        fprintf(stderr, "read %s: expected %zu, observed %zd\n", input_path,
                count, read_buf_rv);
        return false;
      }

      ssize_t write_buf_rv = write(output_fd, buf, count);
      if (write_buf_rv < 0) {
        fprintf(stderr, "write %s: %s\n", output_path, strerror(errno));
        return false;
      } else if (write_buf_rv != count) {
        fprintf(stderr, "write %s: expected %zu, observed %zd\n", output_path,
                count, write_buf_rv);
        return false;
      }
    } else {
      char rep;
      ssize_t read_rep_rv = read(input_fd, &rep, 1);
      if (read_rep_rv < 0) {
        fprintf(stderr, "read %s: %s\n", input_path, strerror(errno));
        return false;
      }

      const size_t count = cmd - 125;
      std::string reps(count, rep);

      ssize_t write_reps_rv = write(output_fd, &reps[0], reps.size());
      if (write_reps_rv < 0) {
        fprintf(stderr, "write %s: %s\n", output_path, strerror(errno));
        return false;
      } else if (write_reps_rv != reps.size()) {
        fprintf(stderr, "write %s: expected %zu, observed %zd\n", output_path,
                reps.size(), write_reps_rv);
        return false;
      }
    }
  } while (read_cmd_rv > 0);

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

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

  return true;
}