Merge pull request #48 from google/length
Stop trusting header totalSfntSize and glyf origLength
This commit is contained in:
@@ -19,7 +19,8 @@ CXXFLAGS += $(COMMON_FLAGS) -std=c++11
|
|||||||
SRCDIR = src
|
SRCDIR = src
|
||||||
|
|
||||||
OUROBJ = font.o glyph.o normalize.o table_tags.o transform.o \
|
OUROBJ = font.o glyph.o normalize.o table_tags.o transform.o \
|
||||||
woff2_dec.o woff2_enc.o woff2_common.o variable_length.o
|
woff2_dec.o woff2_enc.o woff2_common.o woff2_out.o \
|
||||||
|
variable_length.o
|
||||||
|
|
||||||
BROTLI = brotli
|
BROTLI = brotli
|
||||||
ENCOBJ = $(BROTLI)/enc/*.o
|
ENCOBJ = $(BROTLI)/enc/*.o
|
||||||
|
|||||||
+9
-7
@@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
// File IO helpers
|
// File IO helpers.
|
||||||
|
|
||||||
#ifndef WOFF2_FILE_H_
|
#ifndef WOFF2_FILE_H_
|
||||||
#define WOFF2_FILE_H_
|
#define WOFF2_FILE_H_
|
||||||
@@ -22,18 +22,20 @@
|
|||||||
|
|
||||||
namespace woff2 {
|
namespace woff2 {
|
||||||
|
|
||||||
inline std::string GetFileContent(std::string filename) {
|
using std::string;
|
||||||
|
|
||||||
|
|
||||||
|
inline string GetFileContent(string filename) {
|
||||||
std::ifstream ifs(filename.c_str(), std::ios::binary);
|
std::ifstream ifs(filename.c_str(), std::ios::binary);
|
||||||
return std::string(
|
return string(
|
||||||
std::istreambuf_iterator<char>(ifs.rdbuf()),
|
std::istreambuf_iterator<char>(ifs.rdbuf()),
|
||||||
std::istreambuf_iterator<char>());
|
std::istreambuf_iterator<char>());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SetFileContents(std::string filename, std::string content) {
|
inline void SetFileContents(string filename, string::iterator start,
|
||||||
|
string::iterator end) {
|
||||||
std::ofstream ofs(filename.c_str(), std::ios::binary);
|
std::ofstream ofs(filename.c_str(), std::ios::binary);
|
||||||
std::copy(content.begin(),
|
std::copy(start, end, std::ostream_iterator<char>(ofs));
|
||||||
content.end(),
|
|
||||||
std::ostream_iterator<char>(ofs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace woff2
|
} // namespace woff2
|
||||||
|
|||||||
+2
-6
@@ -49,11 +49,7 @@ std::vector<uint32_t> Font::OutputOrderedTags() const {
|
|||||||
output_order.push_back(table.tag);
|
output_order.push_back(table.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alphabetize and do not put loca immediately after glyf
|
// Alphabetize then put loca immediately after glyf
|
||||||
// This violates woff2 spec but results in a font that passes OTS
|
|
||||||
std::sort(output_order.begin(), output_order.end());
|
|
||||||
// TODO(user): change to match spec once browsers are on newer OTS
|
|
||||||
/*
|
|
||||||
auto glyf_loc = std::find(output_order.begin(), output_order.end(),
|
auto glyf_loc = std::find(output_order.begin(), output_order.end(),
|
||||||
kGlyfTableTag);
|
kGlyfTableTag);
|
||||||
auto loca_loc = std::find(output_order.begin(), output_order.end(),
|
auto loca_loc = std::find(output_order.begin(), output_order.end(),
|
||||||
@@ -62,7 +58,7 @@ std::vector<uint32_t> Font::OutputOrderedTags() const {
|
|||||||
output_order.erase(loca_loc);
|
output_order.erase(loca_loc);
|
||||||
output_order.insert(std::find(output_order.begin(), output_order.end(),
|
output_order.insert(std::find(output_order.begin(), output_order.end(),
|
||||||
kGlyfTableTag) + 1, kLocaTableTag);
|
kGlyfTableTag) + 1, kLocaTableTag);
|
||||||
}*/
|
}
|
||||||
|
|
||||||
return output_order;
|
return output_order;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -58,8 +58,7 @@ inline void Store16(int val, size_t* offset, uint8_t* dst) {
|
|||||||
((val & 0xFF) << 8) | ((val & 0xFF00) >> 8);
|
((val & 0xFF) << 8) | ((val & 0xFF00) >> 8);
|
||||||
*offset += 2;
|
*offset += 2;
|
||||||
#elif (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
#elif (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||||
*reinterpret_cast<uint16_t*>(dst + *offset) =
|
*reinterpret_cast<uint16_t*>(dst + *offset) = static_cast<uint16_t>(val);
|
||||||
static_cast<uint16_t>(val);
|
|
||||||
*offset += 2;
|
*offset += 2;
|
||||||
#else
|
#else
|
||||||
dst[(*offset)++] = val >> 8;
|
dst[(*offset)++] = val >> 8;
|
||||||
|
|||||||
+12
-1
@@ -23,7 +23,8 @@ namespace woff2 {
|
|||||||
|
|
||||||
uint32_t ComputeULongSum(const uint8_t* buf, size_t size) {
|
uint32_t ComputeULongSum(const uint8_t* buf, size_t size) {
|
||||||
uint32_t checksum = 0;
|
uint32_t checksum = 0;
|
||||||
for (size_t i = 0; i < size; i += 4) {
|
size_t aligned_size = size & ~3;
|
||||||
|
for (size_t i = 0; i < aligned_size; i += 4) {
|
||||||
#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||||
uint32_t v = *reinterpret_cast<const uint32_t*>(buf + i);
|
uint32_t v = *reinterpret_cast<const uint32_t*>(buf + i);
|
||||||
checksum += (((v & 0xFF) << 24) | ((v & 0xFF00) << 8) |
|
checksum += (((v & 0xFF) << 24) | ((v & 0xFF00) << 8) |
|
||||||
@@ -35,6 +36,16 @@ uint32_t ComputeULongSum(const uint8_t* buf, size_t size) {
|
|||||||
(buf[i + 2] << 8) | buf[i + 3];
|
(buf[i + 2] << 8) | buf[i + 3];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// treat size not aligned on 4 as if it were padded to 4 with 0's
|
||||||
|
if (size != aligned_size) {
|
||||||
|
uint32_t v = 0;
|
||||||
|
for (size_t i = aligned_size; i < size; ++i) {
|
||||||
|
v |= buf[i] << (24 - 8 * (i & 3));
|
||||||
|
}
|
||||||
|
checksum += v;
|
||||||
|
}
|
||||||
|
|
||||||
return checksum;
|
return checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
output.resize(output_size);
|
output.resize(output_size);
|
||||||
|
|
||||||
woff2::SetFileContents(outfilename, output);
|
woff2::SetFileContents(outfilename, output.begin(), output.end());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+493
-489
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include "./woff2_out.h"
|
||||||
|
|
||||||
namespace woff2 {
|
namespace woff2 {
|
||||||
|
|
||||||
@@ -31,6 +32,11 @@ size_t ComputeWOFF2FinalSize(const uint8_t *data, size_t length);
|
|||||||
bool ConvertWOFF2ToTTF(uint8_t *result, size_t result_length,
|
bool ConvertWOFF2ToTTF(uint8_t *result, size_t result_length,
|
||||||
const uint8_t *data, size_t length);
|
const uint8_t *data, size_t length);
|
||||||
|
|
||||||
|
// Decompresses the font into out. Returns true on success.
|
||||||
|
// Works even if WOFF2Header totalSfntSize is wrong.
|
||||||
|
bool ConvertWOFF2ToTTF(const uint8_t *data, size_t length,
|
||||||
|
WOFF2Out* out);
|
||||||
|
|
||||||
} // namespace woff2
|
} // namespace woff2
|
||||||
|
|
||||||
#endif // WOFF2_WOFF2_DEC_H_
|
#endif // WOFF2_WOFF2_DEC_H_
|
||||||
|
|||||||
+12
-18
@@ -17,10 +17,10 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "./file.h"
|
||||||
#include "file.h"
|
|
||||||
#include "./woff2_dec.h"
|
#include "./woff2_dec.h"
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
@@ -31,24 +31,18 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
string filename(argv[1]);
|
string filename(argv[1]);
|
||||||
string outfilename = filename.substr(0, filename.find_last_of(".")) + ".ttf";
|
string outfilename = filename.substr(0, filename.find_last_of(".")) + ".ttf";
|
||||||
fprintf(stdout, "Processing %s => %s\n",
|
|
||||||
filename.c_str(), outfilename.c_str());
|
|
||||||
string input = woff2::GetFileContent(filename);
|
string input = woff2::GetFileContent(filename);
|
||||||
|
const uint8_t* raw_input = reinterpret_cast<const uint8_t*>(input.data());
|
||||||
|
string output(std::min(woff2::ComputeWOFF2FinalSize(raw_input, input.size()),
|
||||||
|
woff2::kDefaultMaxSize), 0);
|
||||||
|
woff2::WOFF2StringOut out(&output);
|
||||||
|
|
||||||
size_t decompressed_size = woff2::ComputeWOFF2FinalSize(
|
const bool ok = woff2::ConvertWOFF2ToTTF(raw_input, input.size(), &out);
|
||||||
reinterpret_cast<const uint8_t*>(input.data()), input.size());
|
|
||||||
string output(decompressed_size, 0);
|
|
||||||
const bool ok = woff2::ConvertWOFF2ToTTF(
|
|
||||||
reinterpret_cast<uint8_t*>(&output[0]), decompressed_size,
|
|
||||||
reinterpret_cast<const uint8_t*>(input.data()), input.size());
|
|
||||||
|
|
||||||
if (!ok) {
|
if (ok) {
|
||||||
fprintf(stderr, "Decompression failed\n");
|
woff2::SetFileContents(outfilename, output.begin(),
|
||||||
return 1;
|
output.begin() + out.Size());
|
||||||
}
|
}
|
||||||
|
return ok ? 0 : 1;
|
||||||
woff2::SetFileContents(outfilename, output);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -23,8 +23,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "./buffer.h"
|
|
||||||
#include "./encode.h"
|
#include "./encode.h"
|
||||||
|
#include "./buffer.h"
|
||||||
#include "./font.h"
|
#include "./font.h"
|
||||||
#include "./normalize.h"
|
#include "./normalize.h"
|
||||||
#include "./round.h"
|
#include "./round.h"
|
||||||
@@ -47,6 +47,7 @@ using std::vector;
|
|||||||
const size_t kWoff2HeaderSize = 48;
|
const size_t kWoff2HeaderSize = 48;
|
||||||
const size_t kWoff2EntrySize = 20;
|
const size_t kWoff2EntrySize = 20;
|
||||||
|
|
||||||
|
|
||||||
bool Compress(const uint8_t* data, const size_t len,
|
bool Compress(const uint8_t* data, const size_t len,
|
||||||
uint8_t* result, uint32_t* result_len,
|
uint8_t* result, uint32_t* result_len,
|
||||||
brotli::BrotliParams::Mode mode, int quality) {
|
brotli::BrotliParams::Mode mode, int quality) {
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Output buffer for WOFF2 decompression.
|
||||||
|
|
||||||
|
#include "./woff2_out.h"
|
||||||
|
|
||||||
|
namespace woff2 {
|
||||||
|
|
||||||
|
WOFF2StringOut::WOFF2StringOut(string* buf)
|
||||||
|
: buf_(buf),
|
||||||
|
max_size_(kDefaultMaxSize),
|
||||||
|
offset_(0) {}
|
||||||
|
|
||||||
|
bool WOFF2StringOut::Write(const void *buf, size_t n) {
|
||||||
|
return Write(buf, offset_, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WOFF2StringOut::Write(const void *buf, size_t offset, size_t n) {
|
||||||
|
if (offset > max_size_ || n > max_size_ - offset) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (offset == buf_->size()) {
|
||||||
|
buf_->append(static_cast<const char*>(buf), n);
|
||||||
|
} else {
|
||||||
|
if (offset + n > buf_->size()) {
|
||||||
|
buf_->append(offset + n - buf_->size(), 0);
|
||||||
|
}
|
||||||
|
buf_->replace(offset, n, static_cast<const char*>(buf), n);
|
||||||
|
}
|
||||||
|
offset_ = std::max(offset_, offset + n);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WOFF2StringOut::SetMaxSize(size_t max_size) {
|
||||||
|
max_size_ = max_size;
|
||||||
|
if (offset_ > max_size_) {
|
||||||
|
offset_ = max_size_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WOFF2MemoryOut::WOFF2MemoryOut(uint8_t* buf, size_t buf_size)
|
||||||
|
: buf_(buf),
|
||||||
|
buf_size_(buf_size),
|
||||||
|
offset_(0) {}
|
||||||
|
|
||||||
|
bool WOFF2MemoryOut::Write(const void *buf, size_t n) {
|
||||||
|
return Write(buf, offset_, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WOFF2MemoryOut::Write(const void *buf, size_t offset, size_t n) {
|
||||||
|
if (offset > buf_size_ || n > buf_size_ - offset) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::memcpy(buf_ + offset, buf, n);
|
||||||
|
offset_ = std::max(offset_, offset + n);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace woff2
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Output buffer for WOFF2 decompression.
|
||||||
|
|
||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Output buffer for WOFF2 decompression.
|
||||||
|
|
||||||
|
#ifndef WOFF2_WOFF2_OUT_H_
|
||||||
|
#define WOFF2_WOFF2_OUT_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include "./port.h"
|
||||||
|
|
||||||
|
namespace woff2 {
|
||||||
|
|
||||||
|
// Suggested max size for output.
|
||||||
|
const size_t kDefaultMaxSize = 30 * 1024 * 1024;
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output interface for the woff2 decoding.
|
||||||
|
*
|
||||||
|
* Writes to arbitrary offsets are supported to facilitate updating offset
|
||||||
|
* table and checksums after tables are ready. Reading the current size is
|
||||||
|
* supported so a 'loca' table can be built up while writing glyphs.
|
||||||
|
*
|
||||||
|
* By default limits size to kDefaultMaxSize.
|
||||||
|
*/
|
||||||
|
class WOFF2Out {
|
||||||
|
public:
|
||||||
|
virtual ~WOFF2Out(void) {}
|
||||||
|
|
||||||
|
// Append n bytes of data from buf.
|
||||||
|
// Return true if all written, false otherwise.
|
||||||
|
virtual bool Write(const void *buf, size_t n) = 0;
|
||||||
|
|
||||||
|
// Write n bytes of data from buf at offset.
|
||||||
|
// Return true if all written, false otherwise.
|
||||||
|
virtual bool Write(const void *buf, size_t offset, size_t n) = 0;
|
||||||
|
|
||||||
|
virtual size_t Size() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expanding memory block for woff2 out. By default limited to kDefaultMaxSize.
|
||||||
|
*/
|
||||||
|
class WOFF2StringOut : public WOFF2Out {
|
||||||
|
public:
|
||||||
|
// Create a writer that writes its data to buf.
|
||||||
|
// buf->size() will grow to at most max_size
|
||||||
|
// buf may be sized (e.g. using EstimateWOFF2FinalSize) or empty.
|
||||||
|
explicit WOFF2StringOut(string* buf);
|
||||||
|
|
||||||
|
bool Write(const void *buf, size_t n) override;
|
||||||
|
bool Write(const void *buf, size_t offset, size_t n) override;
|
||||||
|
size_t Size() override { return offset_; }
|
||||||
|
size_t MaxSize() { return max_size_; }
|
||||||
|
void SetMaxSize(size_t max_size);
|
||||||
|
private:
|
||||||
|
string* buf_;
|
||||||
|
size_t max_size_;
|
||||||
|
size_t offset_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixed memory block for woff2 out.
|
||||||
|
*/
|
||||||
|
class WOFF2MemoryOut : public WOFF2Out {
|
||||||
|
public:
|
||||||
|
// Create a writer that writes its data to buf.
|
||||||
|
WOFF2MemoryOut(uint8_t* buf, size_t buf_size);
|
||||||
|
|
||||||
|
bool Write(const void *buf, size_t n) override;
|
||||||
|
bool Write(const void *buf, size_t offset, size_t n) override;
|
||||||
|
size_t Size() override { return offset_; }
|
||||||
|
private:
|
||||||
|
uint8_t* buf_;
|
||||||
|
size_t buf_size_;
|
||||||
|
size_t offset_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace woff2
|
||||||
|
|
||||||
|
#endif // WOFF2_WOFF2_OUT_H_
|
||||||
Reference in New Issue
Block a user