1// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef OPENTYPE_SANITISER_H_
6#define OPENTYPE_SANITISER_H_
7
8#if defined(_WIN32)
9#include <stdlib.h>
10typedef signed char int8_t;
11typedef unsigned char uint8_t;
12typedef short int16_t;
13typedef unsigned short uint16_t;
14typedef int int32_t;
15typedef unsigned int uint32_t;
16typedef __int64 int64_t;
17typedef unsigned __int64 uint64_t;
18#define ntohl(x) _byteswap_ulong (x)
19#define ntohs(x) _byteswap_ushort (x)
20#define htonl(x) _byteswap_ulong (x)
21#define htons(x) _byteswap_ushort (x)
22#else
23#include <arpa/inet.h>
24#include <stdint.h>
25#endif
26
27#include <algorithm>  // for std::min
28#include <cassert>
29#include <cstddef>
30#include <cstring>
31
32namespace ots {
33
34// -----------------------------------------------------------------------------
35// This is an interface for an abstract stream class which is used for writing
36// the serialised results out.
37// -----------------------------------------------------------------------------
38class OTSStream {
39 public:
40  OTSStream() {
41    ResetChecksum();
42  }
43
44  virtual ~OTSStream() {}
45
46  // This should be implemented to perform the actual write.
47  virtual bool WriteRaw(const void *data, size_t length) = 0;
48
49  bool Write(const void *data, size_t length) {
50    if (!length) return false;
51
52    const size_t orig_length = length;
53    size_t offset = 0;
54    if (chksum_buffer_offset_) {
55      const size_t l =
56        std::min(length, static_cast<size_t>(4) - chksum_buffer_offset_);
57      std::memcpy(chksum_buffer_ + chksum_buffer_offset_, data, l);
58      chksum_buffer_offset_ += l;
59      offset += l;
60      length -= l;
61    }
62
63    if (chksum_buffer_offset_ == 4) {
64      uint32_t chksum;
65      std::memcpy(&chksum, chksum_buffer_, 4);
66      chksum_ += ntohl(chksum);
67      chksum_buffer_offset_ = 0;
68    }
69
70    while (length >= 4) {
71      chksum_ += ntohl(*reinterpret_cast<const uint32_t*>(
72          reinterpret_cast<const uint8_t*>(data) + offset));
73      length -= 4;
74      offset += 4;
75    }
76
77    if (length) {
78      if (chksum_buffer_offset_ != 0) return false;  // not reached
79      if (length > 4) return false;  // not reached
80      std::memcpy(chksum_buffer_,
81             reinterpret_cast<const uint8_t*>(data) + offset, length);
82      chksum_buffer_offset_ = length;
83    }
84
85    return WriteRaw(data, orig_length);
86  }
87
88  virtual bool Seek(off_t position) = 0;
89  virtual off_t Tell() const = 0;
90
91  virtual bool Pad(size_t bytes) {
92    static const uint32_t kZero = 0;
93    while (bytes >= 4) {
94      if (!WriteTag(kZero)) return false;
95      bytes -= 4;
96    }
97    while (bytes) {
98      static const uint8_t kZerob = 0;
99      if (!Write(&kZerob, 1)) return false;
100      bytes--;
101    }
102    return true;
103  }
104
105  bool WriteU8(uint8_t v) {
106    return Write(&v, sizeof(v));
107  }
108
109  bool WriteU16(uint16_t v) {
110    v = htons(v);
111    return Write(&v, sizeof(v));
112  }
113
114  bool WriteS16(int16_t v) {
115    v = htons(v);
116    return Write(&v, sizeof(v));
117  }
118
119  bool WriteU24(uint32_t v) {
120    v = htonl(v);
121    return Write(reinterpret_cast<uint8_t*>(&v)+1, 3);
122  }
123
124  bool WriteU32(uint32_t v) {
125    v = htonl(v);
126    return Write(&v, sizeof(v));
127  }
128
129  bool WriteS32(int32_t v) {
130    v = htonl(v);
131    return Write(&v, sizeof(v));
132  }
133
134  bool WriteR64(uint64_t v) {
135    return Write(&v, sizeof(v));
136  }
137
138  bool WriteTag(uint32_t v) {
139    return Write(&v, sizeof(v));
140  }
141
142  void ResetChecksum() {
143    chksum_ = 0;
144    chksum_buffer_offset_ = 0;
145  }
146
147  uint32_t chksum() const {
148    assert(chksum_buffer_offset_ == 0);
149    return chksum_;
150  }
151
152  struct ChecksumState {
153    uint32_t chksum;
154    uint8_t chksum_buffer[4];
155    unsigned chksum_buffer_offset;
156  };
157
158  ChecksumState SaveChecksumState() const {
159    ChecksumState s;
160    s.chksum = chksum_;
161    s.chksum_buffer_offset = chksum_buffer_offset_;
162    std::memcpy(s.chksum_buffer, chksum_buffer_, 4);
163
164    return s;
165  }
166
167  void RestoreChecksum(const ChecksumState &s) {
168    assert(chksum_buffer_offset_ == 0);
169    chksum_ += s.chksum;
170    chksum_buffer_offset_ = s.chksum_buffer_offset;
171    std::memcpy(chksum_buffer_, s.chksum_buffer, 4);
172  }
173
174 protected:
175  uint32_t chksum_;
176  uint8_t chksum_buffer_[4];
177  unsigned chksum_buffer_offset_;
178};
179
180// -----------------------------------------------------------------------------
181// Process a given OpenType file and write out a sanitised version
182//   output: a pointer to an object implementing the OTSStream interface. The
183//     sanitisied output will be written to this. In the even of a failure,
184//     partial output may have been written.
185//   input: the OpenType file
186//   length: the size, in bytes, of |input|
187// -----------------------------------------------------------------------------
188bool Process(OTSStream *output, const uint8_t *input, size_t length);
189
190// Force to disable debug output even when the library is compiled with
191// -DOTS_DEBUG.
192void DisableDebugOutput();
193
194// Enable WOFF2 support(experimental).
195// TODO(bashi): Remove WOFF2 from OTS.
196void EnableWOFF2();
197
198// Force to disable dropping CBDT/CBLC tables.
199void DoNotDropColorBitmapTables();
200
201}  // namespace ots
202
203#endif  // OPENTYPE_SANITISER_H_
204