130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun/*
230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Copyright 2011 Google Inc. All Rights Reserved.
330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun *
430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Licensed under the Apache License, Version 2.0 (the "License");
530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * you may not use this file except in compliance with the License.
630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * You may obtain a copy of the License at
730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun *
830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun *      http://www.apache.org/licenses/LICENSE-2.0
930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun *
1030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Unless required by applicable law or agreed to in writing, software
1130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * distributed under the License is distributed on an "AS IS" BASIS,
1230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * See the License for the specific language governing permissions and
1430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * limitations under the License.
1530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun */
1630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
1730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <stdio.h>
1830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
1930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <vector>
2030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <string>
2130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <sstream>
2230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
2330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/port/type.h"
2430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "font_subsetter.h"
2530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
2630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Guruntemplate <typename T>
2730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunclass HexTo {
2830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun public:
2930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  explicit HexTo(const char* in) {
3030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    std::stringstream ss;
3130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    ss << std::hex << in;
3230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    ss >> value_;
3330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
3430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  operator T() const { return value_; }
3530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
3630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun private:
3730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  T value_;
3830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun};
3930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
4030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunbool LoadFile(const char* input_file_path, sfntly::ByteVector* input_buffer) {
4130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  assert(input_file_path);
4230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  assert(input_buffer);
4330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
4430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  FILE* input_file = NULL;
4530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined WIN32
4630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  fopen_s(&input_file, input_file_path, "rb");
4730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#else
4830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  input_file = fopen(input_file_path, "rb");
4930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif
5030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (input_file == NULL) {
5130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return false;
5230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
5330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  fseek(input_file, 0, SEEK_END);
5430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  size_t file_size = ftell(input_file);
5530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  fseek(input_file, 0, SEEK_SET);
5630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  input_buffer->resize(file_size);
5730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  size_t bytes_read = fread(&((*input_buffer)[0]), 1, file_size, input_file);
5830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  fclose(input_file);
5930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  return bytes_read == file_size;
6030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
6130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
6230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunbool SaveFile(const char* output_file_path, const unsigned char* output_buffer,
6330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun              int buffer_length) {
6430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  int byte_count = 0;
6530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (buffer_length > 0) {
6630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    FILE* output_file = NULL;
6730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined WIN32
6830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    fopen_s(&output_file, output_file_path, "wb");
6930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#else
7030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    output_file = fopen(output_file_path, "wb");
7130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif
7230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    if (output_file) {
7330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      byte_count = fwrite(output_buffer, 1, buffer_length, output_file);
7430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      fflush(output_file);
7530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      fclose(output_file);
7630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    }
7730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return buffer_length == byte_count;
7830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
7930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  return false;
8030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
8130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
8230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunbool StringToGlyphId(const char* input, std::vector<unsigned int>* glyph_ids) {
8330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  assert(input);
8430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  std::string hex_csv = input;
8530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  size_t start = 0;
8630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  size_t end = hex_csv.find_first_of(",");
8730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  while (end != std::string::npos) {
8830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    glyph_ids->push_back(
8930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun        HexTo<unsigned int>(hex_csv.substr(start, end - start).c_str()));
9030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    start = end + 1;
9130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    end = hex_csv.find_first_of(",", start);
9230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
9330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  glyph_ids->push_back(HexTo<unsigned int>(hex_csv.substr(start).c_str()));
9430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  return glyph_ids->size() > 0;
9530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
9630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
9730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunint main(int argc, char** argv) {
9830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (argc < 5) {
9930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    fprintf(stderr,
10030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun        "Usage: %s <input path> <output path> <font name> <glyph ids>\n",
10130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun        argv[0]);
10230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    fprintf(stderr, "\tGlyph ids are comma separated hex values\n");
10330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    fprintf(stderr, "\te.g. 20,1a,3b,4f\n");
10430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return 0;
10530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
10630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
10730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  sfntly::ByteVector input_buffer;
10830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (!LoadFile(argv[1], &input_buffer)) {
10930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    fprintf(stderr, "ERROR: unable to load font file %s\n", argv[1]);
11030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return 0;
11130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
11230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
11330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  std::vector<unsigned int> glyph_ids;
11430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (!StringToGlyphId(argv[4], &glyph_ids)) {
11530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    fprintf(stderr, "ERROR: unable to parse input glyph id\n");
11630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return 0;
11730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
11830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
11930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  unsigned char* output_buffer = NULL;
12030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  int output_length =
12130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      SfntlyWrapper::SubsetFont(argv[3],
12230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                                &(input_buffer[0]),
12330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                                input_buffer.size(),
12430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                                &(glyph_ids[0]),
12530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                                glyph_ids.size(),
12630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                                &output_buffer);
12730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
12830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  int result = SaveFile(argv[2], output_buffer, output_length) ? 1 : 0;
12930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  delete[] output_buffer;
13030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  return result;
13130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
132