Remove old files; use the ones in woff2/ instead
diff --git a/cpp/.SConstruct.swp b/cpp/.SConstruct.swp
deleted file mode 100644
index 402a853..0000000
--- a/cpp/.SConstruct.swp
+++ /dev/null
Binary files differ
diff --git a/cpp/Inconsolata-Regular.woff2 b/cpp/Inconsolata-Regular.woff2
deleted file mode 100644
index ddfefb3..0000000
--- a/cpp/Inconsolata-Regular.woff2
+++ /dev/null
Binary files differ
diff --git a/cpp/README b/cpp/README
deleted file mode 100644
index 6c40119..0000000
--- a/cpp/README
+++ /dev/null
@@ -1,44 +0,0 @@
-To build:
-
-Check out a recent version of OTS, so that ots-read-only/ is alongside cpp/
-
-Cd into cpp, and run "scons".
-
-Then, decompress a font using ./woff2-decompress font.wof2 > font.ttf .
-
-An example font is provided (Inconsolata-Regular.wof2). In this snapshot,
-it contains no actual compression, but does apply the glyf table transform
-and has the file format and structure as described in the current draft
-of the "WOFF Ultra Condensed file format" doc.
-
-That said, it is possible to get reliable estimates, and at the very least,
-bounds, on the compression efficiency, with the confidence that the
-compression is reversible. Running the compressor and doing a whole-file
-compression with a standard entropy coder such as gzip or lzma will yield
-a file size within a few dozen bytes or so of using a single entropy coded
-stream in the final file format.
-
-Another limitation of the current implementation snapshot is that it
-doesn't implement continue streams. These will follow shortly.
-
-= Building with lzma =
-
-The lzma-enabled build is made with gyp instead of scons. Right now, the build
-requires patching a clean copy of OTS. (And thanks to Bashi for the patch!)
-
-- Download GYP from http://code.google.com/p/gyp/
-- Download clean OTS sources:
-% svn checkout http://ots.googlecode.com/svn/trunk/ ots-read-only
-- Apply patch
-% cd ots-read-only; patch -p0 < ../ots-lzma.patch
-- Run gyp to generate Makefile
-% cd ../cpp; gyp --depth=. -f make woff2.gyp
-- Build
-% make
-
-Now run:
-
-out/Default/woff2-decompress Inconsolata-Regular-lzma.wof2 > i.ttf
-
-We expect the build recipes to be cleaned up before the code is ready for
-production, but this should be good enough for testing.
diff --git a/cpp/SConstruct b/cpp/SConstruct
deleted file mode 100644
index 4ec2e45..0000000
--- a/cpp/SConstruct
+++ /dev/null
@@ -1,52 +0,0 @@
-# Build script for Linux
-# Note: this script DOESN'T include LZMA. Use the gyp-based build instead.
-#
-# Usage:
-#   $ cd ots/test/
-#   $ scons -c         # clean
-#   $ scons            # build
-#
-
-# Since the validator-checker tool might handle malicious font files, all hardening options for recent g++/ld are enabled just in case.
-# See http://wiki.debian.org/Hardening for details.
-env = Environment(CCFLAGS = ['-O2', '-I../ots-read-only/include', '-I../ots-read-only/src', '-I/usr/include/freetype2', '-ggdb', '-Wall', '-W', '-Wno-unused-parameter', '-fno-strict-aliasing', '-fPIE', '-fstack-protector', '-D_FORTIFY_SOURCE=2', '-DOTS_DEBUG'], LINKFLAGS = ['-ggdb', '-Wl,-z,relro', '-Wl,-z,now', '-pie', '-lz'])
- 
-env.Library('libwoff2.a',
-            [
-            'woff2.cc',
-
-            # Just build all of OTS to keep things simple for now. We could
-            # refactor so that we only compile the few support routines from
-            # ots.cc that we need.
-            '../ots-read-only/src/cff.cc',
-	          '../ots-read-only/src/cff_type2_charstring.cc',
-	          '../ots-read-only/src/cmap.cc',
-	          '../ots-read-only/src/cvt.cc',
-	          '../ots-read-only/src/fpgm.cc',
-	          '../ots-read-only/src/gasp.cc',
-	          '../ots-read-only/src/gdef.cc',
-	          '../ots-read-only/src/glyf.cc',
-	          '../ots-read-only/src/gpos.cc',
-	          '../ots-read-only/src/gsub.cc',
-	          '../ots-read-only/src/hdmx.cc',
-	          '../ots-read-only/src/head.cc',
-	          '../ots-read-only/src/hhea.cc',
-	          '../ots-read-only/src/hmtx.cc',
-	          '../ots-read-only/src/kern.cc',
-	          '../ots-read-only/src/layout.cc',
-	          '../ots-read-only/src/loca.cc',
-	          '../ots-read-only/src/ltsh.cc',
-	          '../ots-read-only/src/maxp.cc',
-	          '../ots-read-only/src/metrics.cc',
-	          '../ots-read-only/src/name.cc',
-	          '../ots-read-only/src/os2.cc',
-	          '../ots-read-only/src/ots.cc',
-	          '../ots-read-only/src/post.cc',
-	          '../ots-read-only/src/prep.cc',
-	          '../ots-read-only/src/vdmx.cc',
-	          '../ots-read-only/src/vhea.cc',
-	          '../ots-read-only/src/vmtx.cc',
-	          '../ots-read-only/src/vorg.cc'
-            ])
-
-env.Program('woff2-decompress.cc', LIBS = ['woff2'], LIBPATH='.')
diff --git a/cpp/woff2-decompress.cc b/cpp/woff2-decompress.cc
deleted file mode 100644
index dc9a281..0000000
--- a/cpp/woff2-decompress.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// A very simple commandline tool for decompressing woff2 format files
-// (given as argc[1]), writing the decompressed version to stdout.
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <cstdio>
-#include <cstdlib>
-
-#include "opentype-sanitiser.h"
-#include "woff2.h"
-
-namespace {
-
-int Usage(const char *argv0) {
-  std::fprintf(stderr, "Usage: %s woff2_file > dest_ttf_file\n", argv0);
-  return 1;
-}
-
-}  // namespace
-
-int main(int argc, char **argv) {
-  if (argc != 2) return Usage(argv[0]);
-  if (::isatty(1)) return Usage(argv[0]);
-
-  const int fd = ::open(argv[1], O_RDONLY);
-  if (fd < 0) {
-    ::perror("open");
-    return 1;
-  }
-
-  struct stat st;
-  ::fstat(fd, &st);
-
-  uint8_t *data = new uint8_t[st.st_size];
-  if (::read(fd, data, st.st_size) != st.st_size) {
-    ::perror("read");
-    return 1;
-  }
-  ::close(fd);
-
-  size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, st.st_size);
-  if (decompressed_size == 0) {
-    std::fprintf(stderr, "Error computing decompressed file size!\n");
-    return 1;
-  }
-  uint8_t *buf = new uint8_t[decompressed_size];
-  const bool result = ots::ConvertWOFF2ToTTF(buf, decompressed_size,
-    data, st.st_size);
-
-  if (!result) {
-    std::fprintf(stderr, "Failed to decompress file!\n");
-  }
-  fwrite(buf, 1, decompressed_size, stdout);
-  return !result;
-}
diff --git a/cpp/woff2.cc b/cpp/woff2.cc
deleted file mode 100644
index 6fe543c..0000000
--- a/cpp/woff2.cc
+++ /dev/null
@@ -1,1035 +0,0 @@
-// Copyright (c) 2012 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This is the implementation of decompression of the proposed WOFF Ultra
-// Condensed file format.
-
-// For now, use of LZMA is conditional, because the build is trickier. When
-// that gets all sorted out, we can get rid of these ifdefs.
-#define USE_LZMA
-
-#include <vector>
-
-#ifdef USE_LZMA
-#include "third_party/lzma_sdk/LzmaLib.h"
-#endif
-
-#include <zlib.h>
-
-#include "opentype-sanitiser.h"
-#include "ots-memory-stream.h"
-
-#include "ots.h"
-#include "woff2.h"
-
-namespace {
-
-// simple glyph flags
-const int kGlyfOnCurve = 1 << 0;
-const int kGlyfXShort = 1 << 1;
-const int kGlyfYShort = 1 << 2;
-const int kGlyfRepeat = 1 << 3;
-const int kGlyfThisXIsSame = 1 << 4;
-const int kGlyfThisYIsSame = 1 << 5;
-
-// composite glyph flags
-const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
-const int FLAG_ARGS_ARE_XY_VALUES = 1 << 1;
-const int FLAG_ROUND_XY_TO_GRID = 1 << 2;
-const int FLAG_WE_HAVE_A_SCALE = 1 << 3;
-const int FLAG_RESERVED = 1 << 4;
-const int FLAG_MORE_COMPONENTS = 1 << 5;
-const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
-const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
-const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
-const int FLAG_USE_MY_METRICS = 1 << 9;
-const int FLAG_OVERLAP_COMPOUND = 1 << 10;
-const int FLAG_SCALED_COMPONENT_OFFSET = 1 << 11;
-const int FLAG_UNSCALED_COMPONENT_OFFSET = 1 << 12;
-
-const size_t kSfntHeaderSize = 12;
-const size_t kSfntEntrySize = 16;
-const size_t kCheckSumAdjustmentOffset = 8;
-
-const size_t kEndPtsOfContoursOffset = 10;
-const size_t kCompositeGlyphBegin = 10;
-
-// Note that the byte order is big-endian, not the same as ots.cc
-#define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d)
-
-const unsigned int kWoff2FlagsContinueStream = 1 << 4;
-const unsigned int kWoff2FlagsTransform = 1 << 5;
-
-const size_t kWoff2HeaderSize = 44;
-const size_t kWoff2EntrySize = 20;
-
-const size_t kLzmaHeaderSize = 13;
-
-// Compression type values common to both short and long formats
-const uint32_t kCompressionTypeMask = 0xf;
-const uint32_t kCompressionTypeNone = 0;
-const uint32_t kCompressionTypeGzip = 1;
-const uint32_t kCompressionTypeLzma = 2;
-
-// This is a special value for the short format only, as described in
-// "Design for compressed header format" in draft doc.
-const uint32_t kShortFlagsContinue = 3;
-
-struct Point {
-  int x;
-  int y;
-  bool on_curve;
-};
-
-struct Table {
-  uint32_t tag;
-  uint32_t flags;
-  uint32_t src_offset;
-  uint32_t src_length;
-
-  uint32_t transform_length;
-
-  uint32_t dst_offset;
-  uint32_t dst_length;
-};
-
-// TODO: copied from ots.cc, probably shouldn't be duplicated.
-// Round a value up to the nearest multiple of 4. Don't round the value in the
-// case that rounding up overflows.
-template<typename T> T Round4(T value) {
-  if (std::numeric_limits<T>::max() - value < 3) {
-    return value;
-  }
-  return (value + 3) & ~3;
-}
-
-// Based on section 6.1.1 of MicroType Express draft spec
-bool Read255UShort(ots::Buffer* buf, unsigned int* value) {
-  static const int kWordCode = 253;
-  static const int kOneMoreByteCode2 = 254;
-  static const int kOneMoreByteCode1 = 255;
-  static const int kLowestUCode = 253;
-  uint8_t code = 0;
-  if (!buf->ReadU8(&code)) {
-    return OTS_FAILURE();
-  }
-  if (code == kWordCode) {
-    uint16_t result = 0;
-    if (!buf->ReadU16(&result)) {
-      return OTS_FAILURE();
-    }
-    *value = result;
-    return true;
-  } else if (code == kOneMoreByteCode1) {
-    uint8_t result = 0;
-    if (!buf->ReadU8(&result)) {
-      return OTS_FAILURE();
-    }
-    *value = result + kLowestUCode;
-    return true;
-  } else if (code == kOneMoreByteCode2) {
-    uint8_t result = 0;
-    if (!buf->ReadU8(&result)) {
-      return OTS_FAILURE();
-    }
-    *value = result + kLowestUCode * 2;
-    return true;
-  } else {
-    *value = code;
-    return true;
-  }
-}
-
-bool ReadBase128(ots::Buffer* buf, uint32_t* value) {
-  uint32_t result = 0;
-  for (size_t i = 0; i < 5; ++i) {
-    uint8_t code = 0;
-    if (!buf->ReadU8(&code)) {
-      return OTS_FAILURE();
-    }
-    // If any of the top seven bits are set then we're about to overflow.
-    if (result & 0xe0000000) {
-      return OTS_FAILURE();
-    }
-    result = (result << 7) | (code & 0x7f);
-    if ((code & 0x80) == 0) {
-      *value = result;
-      return true;
-    }
-  }
-  // Make sure not to exceed the size bound
-  return OTS_FAILURE();
-}
-
-size_t StoreU32(uint8_t* dst, size_t offset, uint32_t x) {
-  dst[offset] = x >> 24;
-  dst[offset + 1] = x >> 16;
-  dst[offset + 2] = x >> 8;
-  dst[offset + 3] = x;
-  return offset + 4;
-}
-
-size_t Store16(uint8_t* dst, size_t offset, int x) {
-  dst[offset] = x >> 8;
-  dst[offset + 1] = x;
-  return offset + 2;
-}
-
-int WithSign(int flag, int baseval) {
-  // Precondition: 0 <= baseval < 65536 (to avoid integer overflow)
-  return (flag & 1) ? baseval : -baseval;
-}
-
-bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
-    unsigned int n_points, std::vector<Point>* result,
-    size_t* in_bytes_consumed) {
-  int x = 0;
-  int y = 0;
-
-  if (n_points > in_size) {
-    return OTS_FAILURE();
-  }
-  unsigned int triplet_index = 0;
-
-  for (unsigned int i = 0; i < n_points; ++i) {
-    uint8_t flag = flags_in[i];
-    bool on_curve = !(flag >> 7);
-    flag &= 0x7f;
-    unsigned int n_data_bytes;
-    if (flag < 84) {
-      n_data_bytes = 1;
-    } else if (flag < 120) {
-      n_data_bytes = 2;
-    } else if (flag < 124) {
-      n_data_bytes = 3;
-    } else {
-      n_data_bytes = 4;
-    }
-    if (triplet_index + n_data_bytes > in_size ||
-        triplet_index + n_data_bytes < triplet_index) {
-      return OTS_FAILURE();
-    }
-    int dx, dy;
-    if (flag < 10) {
-      dx = 0;
-      dy = WithSign(flag, ((flag & 14) << 7) + in[triplet_index]);
-    } else if (flag < 20) {
-      dx = WithSign(flag, (((flag - 10) & 14) << 7) + in[triplet_index]);
-      dy = 0;
-    } else if (flag < 84) {
-      int b0 = flag - 20;
-      int b1 = in[triplet_index];
-      dx = WithSign(flag, 1 + (b0 & 0x30) + (b1 >> 4));
-      dy = WithSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f));
-    } else if (flag < 120) {
-      int b0 = flag - 84;
-      dx = WithSign(flag, 1 + ((b0 / 12) << 8) + in[triplet_index]);
-      dy = WithSign(flag >> 1,
-                    1 + (((b0 % 12) >> 2) << 8) + in[triplet_index + 1]);
-    } else if (flag < 124) {
-      int b2 = in[triplet_index + 1];
-      dx = WithSign(flag, (in[triplet_index] << 4) + (b2 >> 4));
-      dy = WithSign(flag >> 1, ((b2 & 0x0f) << 8) + in[triplet_index + 2]);
-    } else {
-      dx = WithSign(flag, (in[triplet_index] << 8) + in[triplet_index + 1]);
-      dy = WithSign(flag >> 1,
-          (in[triplet_index + 2] << 8) + in[triplet_index + 3]);
-    }
-    triplet_index += n_data_bytes;
-    // Possible overflow but coordinate values are not security sensitive
-    x += dx;
-    y += dy;
-    result->push_back(Point());
-    Point& back = result->back();
-    back.x = x;
-    back.y = y;
-    back.on_curve = on_curve;
-  }
-  *in_bytes_consumed = triplet_index;
-  return true;
-}
-
-// This function stores just the point data. On entry, dst points to the
-// beginning of a simple glyph. Returns true on success.
-bool StorePoints(const std::vector<Point>& points,
-    unsigned int n_contours, unsigned int instruction_length,
-    uint8_t* dst, size_t dst_size, size_t* glyph_size) {
-  // I believe that n_contours < 65536, in which case this is safe. However, a
-  // comment and/or an assert would be good.
-  unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 +
-    instruction_length;
-  int last_flag = -1;
-  int repeat_count = 0;
-  int last_x = 0;
-  int last_y = 0;
-  unsigned int x_bytes = 0;
-  unsigned int y_bytes = 0;
-
-  for (unsigned int i = 0; i < points.size(); ++i) {
-    const Point& point = points[i];
-    int flag = point.on_curve ? kGlyfOnCurve : 0;
-    int dx = point.x - last_x;
-    int dy = point.y - last_y;
-    if (dx == 0) {
-      flag |= kGlyfThisXIsSame;
-    } else if (dx > -256 && dx < 256) {
-      flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0);
-      x_bytes += 1;
-    } else {
-      x_bytes += 2;
-    }
-    if (dy == 0) {
-      flag |= kGlyfThisYIsSame;
-    } else if (dy > -256 && dy < 256) {
-      flag |= kGlyfYShort | (dy > 0 ? kGlyfThisYIsSame : 0);
-      y_bytes += 1;
-    } else {
-      y_bytes += 2;
-    }
-
-    if (flag == last_flag && repeat_count != 255) {
-      dst[flag_offset - 1] |= kGlyfRepeat;
-      repeat_count++;
-    } else {
-      if (repeat_count != 0) {
-        if (flag_offset >= dst_size) {
-          return OTS_FAILURE();
-        }
-        dst[flag_offset++] = repeat_count;
-      }
-      if (flag_offset >= dst_size) {
-        return OTS_FAILURE();
-      }
-      dst[flag_offset++] = flag;
-      repeat_count = 0;
-    }
-    last_x = point.x;
-    last_y = point.y;
-    last_flag = flag;
-  }
-
-  if (repeat_count != 0) {
-    if (flag_offset >= dst_size) {
-      return OTS_FAILURE();
-    }
-    dst[flag_offset++] = repeat_count;
-  }
-  unsigned int xy_bytes = x_bytes + y_bytes;
-  if (xy_bytes < x_bytes ||
-      flag_offset + xy_bytes < flag_offset ||
-      flag_offset + xy_bytes > dst_size) {
-    return OTS_FAILURE();
-  }
-
-  int x_offset = flag_offset;
-  int y_offset = flag_offset + x_bytes;
-  last_x = 0;
-  last_y = 0;
-  for (unsigned int i = 0; i < points.size(); ++i) {
-    int dx = points[i].x - last_x;
-    if (dx == 0) {
-      // pass
-    } else if (dx > -256 && dx < 256) {
-      dst[x_offset++] = std::abs(dx);
-    } else {
-      // will always fit for valid input, but overflow is harmless
-      x_offset = Store16(dst, x_offset, dx);
-    }
-    last_x += dx;
-    int dy = points[i].y - last_y;
-    if (dy == 0) {
-      // pass
-    } else if (dy > -256 && dy < 256) {
-      dst[y_offset++] = std::abs(dy);
-    } else {
-      y_offset = Store16(dst, y_offset, dy);
-    }
-    last_y += dy;
-  }
-  *glyph_size = y_offset;
-  return true;
-}
-
-// Compute the bounding box of the coordinates, and store into a glyf buffer.
-// A precondition is that there are at least 10 bytes available.
-void ComputeBbox(const std::vector<Point>& points, uint8_t* dst) {
-  int x_min = 0;
-  int y_min = 0;
-  int x_max = 0;
-  int y_max = 0;
-  
-  for (unsigned int i = 0; i < points.size(); ++i) {
-    int x = points[i].x;
-    int y = points[i].y;
-    if (i == 0 || x < x_min) x_min = x;
-    if (i == 0 || x > x_max) x_max = x;
-    if (i == 0 || y < y_min) y_min = y;
-    if (i == 0 || y > y_max) y_max = y;
-  }
-  size_t offset = 2;
-  offset = Store16(dst, offset, x_min);
-  offset = Store16(dst, offset, y_min);
-  offset = Store16(dst, offset, x_max);
-  offset = Store16(dst, offset, y_max);
-}
-
-// Process entire bbox stream. This is done as a separate pass to allow for
-// composite bbox computations (an optional more aggressive transform).
-bool ProcessBboxStream(ots::Buffer* bbox_stream, unsigned int n_glyphs,
-    const std::vector<uint32_t>& loca_values, uint8_t* glyf_buf,
-    size_t glyf_buf_length) {
-  const uint8_t* buf = bbox_stream->buffer();
-  if (n_glyphs >= 65536 || loca_values.size() != n_glyphs + 1) {
-    return OTS_FAILURE();
-  }
-  // Safe because n_glyphs is bounded
-  unsigned int bitmap_length = ((n_glyphs + 31) >> 5) << 2;
-  if (!bbox_stream->Skip(bitmap_length)) {
-    return OTS_FAILURE();
-  }
-  for (unsigned int i = 0; i < n_glyphs; ++i) {
-    if (buf[i >> 3] & (0x80 >> (i & 7))) {
-      uint32_t loca_offset = loca_values[i];
-      if (loca_values[i + 1] - loca_offset < kEndPtsOfContoursOffset) {
-        return OTS_FAILURE();
-      }
-      if (glyf_buf_length < 2 + 10 ||
-          loca_offset > glyf_buf_length - 2 - 10) {
-        return OTS_FAILURE();
-      }
-      if (!bbox_stream->Read(glyf_buf + loca_offset + 2, 8)) {
-        return OTS_FAILURE();
-      }
-    }
-  }
-  return true;
-}
-
-bool ProcessComposite(ots::Buffer* composite_stream, uint8_t* dst,
-    size_t dst_size, size_t* glyph_size, bool* have_instructions) {
-  size_t start_offset = composite_stream->offset();
-  bool we_have_instructions = false;
-
-  uint16_t flags = FLAG_MORE_COMPONENTS;
-  while (flags & FLAG_MORE_COMPONENTS) {
-    if (!composite_stream->ReadU16(&flags)) {
-      return OTS_FAILURE();
-    }
-    we_have_instructions |= (flags & FLAG_WE_HAVE_INSTRUCTIONS) != 0;
-    size_t arg_size = 2;  // glyph index
-    if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) {
-      arg_size += 4;
-    } else {
-      arg_size += 2;
-    }
-    if (flags & FLAG_WE_HAVE_A_SCALE) {
-      arg_size += 2;
-    } else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
-      arg_size += 4;
-    } else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) {
-      arg_size += 8;
-    }
-    if (!composite_stream->Skip(arg_size)) {
-      return OTS_FAILURE();
-    }
-  }
-  size_t composite_glyph_size = composite_stream->offset() - start_offset;
-  if (composite_glyph_size + kCompositeGlyphBegin > dst_size) {
-    return OTS_FAILURE();
-  }
-  Store16(dst, 0, 0xffff);  // nContours = -1 for composite glyph
-  std::memcpy(dst + kCompositeGlyphBegin,
-      composite_stream->buffer() + start_offset,
-      composite_glyph_size);
-  *glyph_size = kCompositeGlyphBegin + composite_glyph_size;
-  *have_instructions = we_have_instructions;
-  return true;
-}
-
-// Build TrueType loca table
-bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format,
-    uint8_t* dst, size_t dst_size) {
-  const uint64_t loca_size = loca_values.size();
-  const uint64_t offset_size = index_format ? 4 : 2;
-  if ((loca_size << 2) >> 2 != loca_size) {
-    return OTS_FAILURE();
-  }
-  if (offset_size * loca_size > dst_size) {
-    return OTS_FAILURE();
-  }
-  size_t offset = 0;
-  for (size_t i = 0; i < loca_values.size(); ++i) {
-    uint32_t value = loca_values[i];
-    if (index_format) {
-      offset = StoreU32(dst, offset, value);
-    } else {
-      offset = Store16(dst, offset, value >> 1);
-    }
-  }
-  return true;
-}
-
-// Reconstruct entire glyf table based on transformed original
-bool ReconstructGlyf(const uint8_t* data, size_t data_size,
-    uint8_t* dst, size_t dst_size,
-    uint8_t* loca_buf, size_t loca_size) {
-  static const int kNumSubStreams = 7;
-  ots::Buffer file(data, data_size);
-  uint32_t version;
-  std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
-
-  if (!file.ReadU32(&version)) {
-    return OTS_FAILURE();
-  }
-  uint16_t num_glyphs;
-  uint16_t index_format;
-  if (!file.ReadU16(&num_glyphs) ||
-      !file.ReadU16(&index_format)) {
-    return OTS_FAILURE();
-  }
-  unsigned int offset = (2 + kNumSubStreams) * 4;
-  if (offset > data_size) {
-    return OTS_FAILURE();
-  }
-  // Invariant from here on: data_size >= offset
-  for (int i = 0; i < kNumSubStreams; ++i) {
-    uint32_t substream_size;
-    if (!file.ReadU32(&substream_size)) {
-      return OTS_FAILURE();
-    }
-    if (substream_size > data_size - offset) {
-      return OTS_FAILURE();
-    }
-    substreams[i] = std::make_pair(data + offset, substream_size);
-    offset += substream_size;
-  }
-  ots::Buffer n_contour_stream(substreams[0].first, substreams[0].second);
-  ots::Buffer n_points_stream(substreams[1].first, substreams[1].second);
-  ots::Buffer flag_stream(substreams[2].first, substreams[2].second);
-  ots::Buffer glyph_stream(substreams[3].first, substreams[3].second);
-  ots::Buffer composite_stream(substreams[4].first, substreams[4].second);
-  ots::Buffer bbox_stream(substreams[5].first, substreams[5].second);
-  ots::Buffer instruction_stream(substreams[6].first, substreams[6].second);
-  
-  std::vector<uint32_t> loca_values(num_glyphs + 1);
-  std::vector<unsigned int> n_points_vec;
-  std::vector<Point> points;
-  uint32_t loca_offset = 0;
-  for (unsigned int i = 0; i < num_glyphs; ++i) {
-    size_t glyph_size = 0;
-    uint16_t n_contours = 0;
-    if (!n_contour_stream.ReadU16(&n_contours)) {
-      return OTS_FAILURE();
-    }
-    uint8_t* glyf_dst = dst + loca_offset;
-    size_t glyf_dst_size = dst_size - loca_offset;
-    if (n_contours == 0xffff) {
-      // composite glyph
-      bool have_instructions = false;
-      unsigned int instruction_size = 0;
-      if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size,
-            &glyph_size, &have_instructions)) {
-        return OTS_FAILURE();
-      }
-      if (have_instructions) {
-        if (!Read255UShort(&glyph_stream, &instruction_size)) {
-          return OTS_FAILURE();
-        }
-        if (instruction_size + 2 > glyf_dst_size - glyph_size) {
-          return OTS_FAILURE();
-        }
-        Store16(glyf_dst, glyph_size, instruction_size);
-        if (!instruction_stream.Read(glyf_dst + glyph_size + 2,
-              instruction_size)) {
-          return OTS_FAILURE();
-        }
-        glyph_size += instruction_size + 2;
-      }
-    } else if (n_contours > 0) {
-      // simple glyph
-      n_points_vec.clear();
-      points.clear();
-      unsigned int total_n_points = 0;
-      unsigned int n_points_contour;
-      for (unsigned int j = 0; j < n_contours; ++j) {
-        if (!Read255UShort(&n_points_stream, &n_points_contour)) {
-          return OTS_FAILURE();
-        }
-        n_points_vec.push_back(n_points_contour);
-        if (total_n_points + n_points_contour < total_n_points) {
-          return OTS_FAILURE();
-        }
-        total_n_points += n_points_contour;
-      }
-      unsigned int flag_size = total_n_points;
-      if (flag_size > flag_stream.length() - flag_stream.offset()) {
-        return OTS_FAILURE();
-      }
-      const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset();
-      const uint8_t* triplet_buf = glyph_stream.buffer() +
-        glyph_stream.offset();
-      size_t triplet_size = glyph_stream.length() - glyph_stream.offset();
-      size_t triplet_bytes_consumed = 0;
-      if (!TripletDecode(flags_buf, triplet_buf, triplet_size, total_n_points,
-            &points, &triplet_bytes_consumed)) {
-        return OTS_FAILURE();
-      }
-      const uint32_t header_and_endpts_contours_size =
-          kEndPtsOfContoursOffset + 2 * n_contours;
-      if (glyf_dst_size < header_and_endpts_contours_size) {
-        return OTS_FAILURE();
-      }
-      Store16(glyf_dst, 0, n_contours);
-      ComputeBbox(points, glyf_dst);
-      size_t offset = kEndPtsOfContoursOffset;
-      int end_point = -1;
-      for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) {
-        end_point += n_points_vec[contour_ix];
-        if (end_point >= 65536) {
-          return OTS_FAILURE();
-        }
-        offset = Store16(glyf_dst, offset, end_point);
-      }
-      if (!flag_stream.Skip(flag_size)) {
-        return OTS_FAILURE();
-      }
-      if (!glyph_stream.Skip(triplet_bytes_consumed)) {
-        return OTS_FAILURE();
-      }
-      unsigned int instruction_size;
-      if (!Read255UShort(&glyph_stream, &instruction_size)) {
-        return OTS_FAILURE();
-      }
-      if (glyf_dst_size - header_and_endpts_contours_size <
-          instruction_size + 2) {
-        return OTS_FAILURE();
-      }
-      uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size;
-      Store16(instruction_dst, 0, instruction_size);
-      if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) {
-        return OTS_FAILURE();
-      }
-      if (!StorePoints(points, n_contours, instruction_size,
-            glyf_dst, glyf_dst_size, &glyph_size)) {
-        return OTS_FAILURE();
-      }
-    } else {
-      glyph_size = 0;
-    }
-    loca_values[i] = loca_offset;
-    if (glyph_size + 3 < glyph_size) {
-      return OTS_FAILURE();
-    }
-    glyph_size = Round4(glyph_size);
-    if (glyph_size > dst_size - loca_offset) {
-      // This shouldn't happen, but this test defensively maintains the
-      // invariant that loca_offset <= dst_size.
-      return OTS_FAILURE();
-    }
-    loca_offset += glyph_size;
-  }
-  loca_values[num_glyphs] = loca_offset;
-  if (!ProcessBboxStream(&bbox_stream, num_glyphs, loca_values,
-          dst, dst_size)) {
-    return OTS_FAILURE();
-  }
-  return StoreLoca(loca_values, index_format, loca_buf, loca_size);
-}
-
-// This is linear search, but could be changed to binary because we
-// do have a guarantee that the tables are sorted by tag. But the total
-// cpu time is expected to be very small in any case.
-const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) {
-  size_t n_tables = tables.size();
-  for (size_t i = 0; i < n_tables; ++i) {
-    if (tables[i].tag == tag) {
-      return &tables[i];
-    }
-  }
-  return NULL;
-}
-
-bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag,
-    const uint8_t* transformed_buf, size_t transformed_size,
-    uint8_t* dst, size_t dst_length) {
-  if (tag == TAG('g', 'l', 'y', 'f')) {
-    const Table* glyf_table = FindTable(tables, tag);
-    const Table* loca_table = FindTable(tables, TAG('l', 'o', 'c', 'a'));
-    if (glyf_table == NULL || loca_table == NULL) {
-      return OTS_FAILURE();
-    }
-    if (static_cast<uint64_t>(glyf_table->dst_offset + glyf_table->dst_length) >
-        dst_length) {
-      return OTS_FAILURE();
-    }
-    if (static_cast<uint64_t>(loca_table->dst_offset + loca_table->dst_length) >
-        dst_length) {
-      return OTS_FAILURE();
-    }
-    return ReconstructGlyf(transformed_buf, transformed_size,
-        dst + glyf_table->dst_offset, glyf_table->dst_length,
-        dst + loca_table->dst_offset, loca_table->dst_length);
-  } else if (tag == TAG('l', 'o', 'c', 'a')) {
-    // processing was already done by glyf table, but validate
-    if (!FindTable(tables, TAG('g', 'l', 'y', 'f'))) {
-      return OTS_FAILURE();
-    }
-  } else {
-    // transform for the tag is not known
-    return OTS_FAILURE();
-  }
-  return true;
-}
-
-uint32_t ComputeChecksum(const uint8_t* buf, size_t size) {
-  uint32_t checksum = 0;
-  for (size_t i = 0; i < size; i += 4) {
-    // We assume the addition is mod 2^32, which is valid because unsigned
-    checksum += (buf[i] << 24) | (buf[i + 1] << 16) |
-      (buf[i + 2] << 8) | buf[i + 3];
-  }
-  return checksum;
-}
-
-bool FixChecksums(const std::vector<Table>& tables, uint8_t* dst) {
-  const Table* head_table = FindTable(tables, TAG('h', 'e', 'a', 'd'));
-  if (head_table == NULL ||
-      head_table->dst_length < kCheckSumAdjustmentOffset + 4) {
-    return OTS_FAILURE();
-  }
-  size_t adjustment_offset = head_table->dst_offset + kCheckSumAdjustmentOffset;
-  StoreU32(dst, adjustment_offset, 0);
-  size_t n_tables = tables.size();
-  uint32_t file_checksum = 0;
-  for (size_t i = 0; i < n_tables; ++i) {
-    const Table* table = &tables[i];
-    size_t table_length = table->dst_length;
-    uint8_t* table_data = dst + table->dst_offset;
-    uint32_t checksum = ComputeChecksum(table_data, table_length);
-    StoreU32(dst, kSfntHeaderSize + i * kSfntEntrySize + 4, checksum);
-    file_checksum += checksum;
-  }
-  file_checksum += ComputeChecksum(dst,
-      kSfntHeaderSize + kSfntEntrySize * n_tables);
-  uint32_t checksum_adjustment = 0xb1b0afba - file_checksum;
-  StoreU32(dst, adjustment_offset, checksum_adjustment);
-  return true;
-}
-
-bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
-    const uint8_t* src_buf, size_t src_size, uint32_t compression_type) {
-  if (compression_type == kCompressionTypeGzip) {
-    uLongf uncompressed_length = dst_size;
-    int r = uncompress(reinterpret_cast<Bytef *>(dst_buf), &uncompressed_length,
-        src_buf, src_size);
-    if (r != Z_OK || uncompressed_length != dst_size) {
-      return OTS_FAILURE();
-    }
-    return true;
-#ifdef USE_LZMA
-  } else if (compression_type == kCompressionTypeLzma) {
-    if (src_size < kLzmaHeaderSize) {
-      // Make sure we have at least a full Lzma header
-      return OTS_FAILURE();
-    }
-    // TODO: check that size matches (or elide size?)
-    size_t uncompressed_size = dst_size;
-    size_t compressed_size = src_size;
-    int result = LzmaUncompress(dst_buf, &dst_size,
-        src_buf + kLzmaHeaderSize, &compressed_size,
-        src_buf, LZMA_PROPS_SIZE);
-    if (result != SZ_OK || uncompressed_size != dst_size) {
-      return OTS_FAILURE();
-    }
-    return true;
-#endif
-  }
-  // Unknown compression type
-  return OTS_FAILURE();
-}
-
-bool ReadLongDirectory(ots::Buffer* file, std::vector<Table>* tables,
-    size_t num_tables) {
-  for (size_t i = 0; i < num_tables; ++i) {
-    Table* table = &(*tables)[i];
-    if (!file->ReadU32(&table->tag) ||
-        !file->ReadU32(&table->flags) ||
-        !file->ReadU32(&table->src_length) ||
-        !file->ReadU32(&table->transform_length) ||
-        !file->ReadU32(&table->dst_length)) {
-      return OTS_FAILURE();
-    }
-  }
-  return true;
-}
-
-const uint32_t known_tags[29] = {
-  TAG('c', 'm', 'a', 'p'),  // 0
-  TAG('h', 'e', 'a', 'd'),  // 1
-  TAG('h', 'h', 'e', 'a'),  // 2
-  TAG('h', 'm', 't', 'x'),  // 3
-  TAG('m', 'a', 'x', 'p'),  // 4
-  TAG('n', 'a', 'm', 'e'),  // 5
-  TAG('O', 'S', '/', '2'),  // 6
-  TAG('p', 'o', 's', 't'),  // 7
-  TAG('c', 'v', 't', ' '),  // 8
-  TAG('f', 'p', 'g', 'm'),  // 9
-  TAG('g', 'l', 'y', 'f'),  // 10
-  TAG('l', 'o', 'c', 'a'),  // 11
-  TAG('p', 'r', 'e', 'p'),  // 12
-  TAG('C', 'F', 'F', ' '),  // 13
-  TAG('V', 'O', 'R', 'G'),  // 14
-  TAG('E', 'B', 'D', 'T'),  // 15
-  TAG('E', 'B', 'L', 'C'),  // 16
-  TAG('g', 'a', 's', 'p'),  // 17
-  TAG('h', 'd', 'm', 'x'),  // 18
-  TAG('k', 'e', 'r', 'n'),  // 19
-  TAG('L', 'T', 'S', 'H'),  // 20
-  TAG('P', 'C', 'L', 'T'),  // 21
-  TAG('V', 'D', 'M', 'X'),  // 22
-  TAG('v', 'h', 'e', 'a'),  // 23
-  TAG('v', 'm', 't', 'x'),  // 24
-  TAG('B', 'A', 'S', 'E'),  // 25
-  TAG('G', 'D', 'E', 'F'),  // 26
-  TAG('G', 'P', 'O', 'S'),  // 27
-  TAG('G', 'S', 'U', 'B'),  // 28
-};
-
-bool ReadShortDirectory(ots::Buffer* file, std::vector<Table>* tables,
-    size_t num_tables) {
-  uint32_t last_compression_type = 0;
-  for (size_t i = 0; i < num_tables; ++i) {
-    Table* table = &(*tables)[i];
-    uint8_t flag_byte;
-    if (!file->ReadU8(&flag_byte)) {
-      return OTS_FAILURE();
-    }
-    uint32_t tag;
-    if ((flag_byte & 0x1f) == 0x1f) {
-      if (!file->ReadU32(&tag)) {
-        return OTS_FAILURE();
-      }
-    } else {
-      if ((flag_byte & 0x1f) >= (sizeof(known_tags) / sizeof(known_tags[0]))) {
-        return OTS_FAILURE();
-      }
-      tag = known_tags[flag_byte & 0x1f];
-    }
-    uint32_t flags = flag_byte >> 6;
-    if (flags == kShortFlagsContinue) {
-      flags = last_compression_type | kWoff2FlagsContinueStream;
-    } else {
-      if (flags == kCompressionTypeNone ||
-          flags == kCompressionTypeGzip ||
-          flags == kCompressionTypeLzma) {
-        last_compression_type = flags;
-      } else {
-        return OTS_FAILURE();
-      }
-    }
-    if ((flag_byte & 0x20) != 0) {
-      flags |= kWoff2FlagsTransform;
-    }
-    uint32_t dst_length;
-    if (!ReadBase128(file, &dst_length)) {
-      return OTS_FAILURE();
-    }
-    uint32_t transform_length = dst_length;
-    if ((flags & kWoff2FlagsTransform) != 0) {
-      if (!ReadBase128(file, &transform_length)) {
-        return OTS_FAILURE();
-      }
-    }
-    uint32_t src_length = transform_length;
-    if ((flag_byte >> 6) == 1 || (flag_byte >> 6) == 2) {
-      if (!ReadBase128(file, &src_length)) {
-        return OTS_FAILURE();
-      }
-    }
-    table->tag = tag;
-    table->flags = flags;
-    table->src_length = src_length;
-    table->transform_length = transform_length;
-    table->dst_length = dst_length;
-  }
-  return true;
-}
-
-}  // namespace
-
-namespace ots {
-
-size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
-  ots::Buffer file(data, length);
-  uint32_t total_length;
-
-  if (!file.Skip(16) ||
-      !file.ReadU32(&total_length)) {
-    return 0;
-  }
-  return total_length;
-}
-
-bool ConvertWOFF2ToTTF(uint8_t* result, size_t result_length,
-                       const uint8_t* data, size_t length) {
-  static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2"
-  ots::Buffer file(data, length);
-
-  uint32_t signature;
-  uint32_t flavor;
-  if (!file.ReadU32(&signature) || signature != kWoff2Signature ||
-      !file.ReadU32(&flavor)) {
-    return OTS_FAILURE();
-  }
-
-  // TODO(bashi): Should call IsValidVersionTag() here.
-
-  uint32_t reported_length;
-  if (!file.ReadU32(&reported_length) || length != reported_length) {
-    return OTS_FAILURE();
-  }
-  uint16_t num_tables;
-  if (!file.ReadU16(&num_tables) || !num_tables) {
-    return OTS_FAILURE();
-  }
-  // We don't care about these fields of the header:
-  //   uint16_t reserved
-  //   uint32_t total_sfnt_size
-  //   uint16_t major_version, minor_version
-  //   uint32_t meta_offset, meta_length, meta_orig_length
-  //   uint32_t priv_offset, priv_length
-  if (!file.Skip(30)) {
-    return OTS_FAILURE();
-  }
-  std::vector<Table> tables(num_tables);
-  // Note: change below to ReadLongDirectory to enable long format.
-  if (!ReadShortDirectory(&file, &tables, num_tables)) {
-    return OTS_FAILURE();
-  }
-  uint64_t src_offset = file.offset();
-  uint64_t dst_offset = kSfntHeaderSize +
-      kSfntEntrySize * static_cast<uint64_t>(num_tables);
-  uint64_t uncompressed_sum = 0;
-  for (uint16_t i = 0; i < num_tables; ++i) {
-    Table* table = &tables[i];
-    table->src_offset = src_offset;
-    src_offset += table->src_length;
-    if (src_offset > std::numeric_limits<uint32_t>::max()) {
-      return OTS_FAILURE();
-    }
-    src_offset = Round4(src_offset);  // TODO: reconsider
-    table->dst_offset = dst_offset;
-    dst_offset += table->dst_length;
-    if (dst_offset > std::numeric_limits<uint32_t>::max()) {
-      return OTS_FAILURE();
-    }
-    dst_offset = Round4(dst_offset);
-    if ((table->flags & kCompressionTypeMask) != kCompressionTypeNone) {
-      uncompressed_sum += table->src_length;
-      if (uncompressed_sum > std::numeric_limits<uint32_t>::max()) {
-        return OTS_FAILURE();
-      }
-    }
-  }
-  // Enforce same 30M limit on uncompressed tables as OTS
-  if (uncompressed_sum > 30 * 1024 * 1024) {
-    return OTS_FAILURE();
-  }
-  if (src_offset > length || dst_offset > result_length) {
-    return OTS_FAILURE();
-  }
-
-  const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables;
-  if (sfnt_header_and_table_directory_size > result_length) {
-    return OTS_FAILURE();
-  }
-
-  // Start building the font
-  size_t offset = 0;
-  offset = StoreU32(result, offset, flavor);
-  offset = Store16(result, offset, num_tables);
-  unsigned max_pow2 = 0;
-  while (1u << (max_pow2 + 1) <= num_tables) {
-    max_pow2++;
-  }
-  const uint16_t output_search_range = (1u << max_pow2) << 4;
-  offset = Store16(result, offset, output_search_range);
-  offset = Store16(result, offset, max_pow2);
-  offset = Store16(result, offset, (num_tables << 4) - output_search_range);
-  for (uint16_t i = 0; i < num_tables; ++i) {
-    const Table* table = &tables[i];
-    offset = StoreU32(result, offset, table->tag);
-    offset = StoreU32(result, offset, 0);  // checksum, to fill in later
-    offset = StoreU32(result, offset, table->dst_offset);
-    offset = StoreU32(result, offset, table->dst_length);
-  }
-  std::vector<uint8_t> uncompressed_buf;
-  bool continue_valid = false;
-  for (uint16_t i = 0; i < num_tables; ++i) {
-    const Table* table = &tables[i];
-    uint32_t flags = table->flags;
-    const uint8_t* src_buf = data + table->src_offset;
-    uint32_t compression_type = flags & kCompressionTypeMask;
-    const uint8_t* transform_buf = NULL;
-    size_t transform_length = table->transform_length;
-    if ((flags & kWoff2FlagsContinueStream) != 0) {
-      if (!continue_valid) {
-        return OTS_FAILURE();
-      }
-    } else if (compression_type == kCompressionTypeNone) {
-      if (transform_length != table->src_length) {
-        return OTS_FAILURE();
-      }
-      transform_buf = src_buf;
-      continue_valid = false;
-    } else if ((flags & kWoff2FlagsContinueStream) == 0) {
-      uint64_t total_size = transform_length;
-      for (uint16_t j = i + 1; j < num_tables; ++j) {
-        if ((tables[j].flags & kWoff2FlagsContinueStream) == 0) {
-          break;
-        }
-        total_size += tables[j].transform_length;
-        if (total_size > std::numeric_limits<uint32_t>::max()) {
-          return OTS_FAILURE();
-        }
-      }
-      uncompressed_buf.resize(total_size);
-      if (!Woff2Uncompress(&uncompressed_buf[0], total_size,
-          src_buf, table->src_length, compression_type)) {
-        return OTS_FAILURE();
-      }
-      transform_buf = &uncompressed_buf[0];
-      continue_valid = true;
-    } else {
-      return OTS_FAILURE();
-    }
-
-    if ((flags & kWoff2FlagsTransform) == 0) {
-      if (transform_length != table->dst_length) {
-        return OTS_FAILURE();
-      }
-      if (static_cast<uint64_t>(table->dst_offset + transform_length) >
-          result_length) {
-        return OTS_FAILURE();
-      }
-      std::memcpy(result + table->dst_offset, transform_buf,
-          transform_length);
-    } else {
-      if (!ReconstructTransformed(tables, table->tag,
-            transform_buf, transform_length, result, result_length)) {
-        return OTS_FAILURE();
-      }
-    }
-    if (continue_valid) {
-      transform_buf += transform_length;
-      if (transform_buf > &uncompressed_buf[uncompressed_buf.size()]) {
-        return OTS_FAILURE();
-      }
-    }
-  }
-
-  return FixChecksums(tables, result);
-}
-
-}  // namespace ots
diff --git a/cpp/woff2.gyp b/cpp/woff2.gyp
deleted file mode 100644
index 6fd3dc9..0000000
--- a/cpp/woff2.gyp
+++ /dev/null
@@ -1,43 +0,0 @@
-{
-  'variables': {
-    'ots_include_dirs': [
-       # This isn't particularly elegant, but it works
-       '../ots-read-only/include',
-       '../ots-read-only/src',
-     ],
-  },
-  'target_defaults': {
-    'defines': [
-      'OTS_DEBUG',
-    ],
-  },
-  'targets': [
-    {
-      'target_name': 'woff2',
-      'type': 'static_library',
-      'sources': [
-        'woff2.cc',
-      ],
-      'include_dirs': [
-        '<@(ots_include_dirs)',
-      ],
-      'dependencies': [
-        '../ots-read-only/ots-standalone.gyp:ots',
-      ],
-    },
-    {
-      'target_name': 'woff2-decompress',
-      'type': 'executable',
-      'sources': [
-        'woff2-decompress.cc',
-      ],
-      'include_dirs': [
-        '<@(ots_include_dirs)',
-      ],
-      'dependencies': [
-        'woff2',
-      ],
-    },
-  ],
-}
-
diff --git a/cpp/woff2.h b/cpp/woff2.h
deleted file mode 100644
index 64ae6df..0000000
--- a/cpp/woff2.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2012 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef OTS_WOFF2_H_
-#define OTS_WOFF2_H_
-
-namespace ots {
-
-// Compute the size of the final uncompressed font, or 0 on error.
-size_t ComputeWOFF2FinalSize(const uint8_t *data, size_t length);
-
-// Decompresses the font into the target buffer. The result_length should
-// be the same as determined by ComputeFinalSize(). Returns true on successful
-// decompression.
-bool ConvertWOFF2ToTTF(uint8_t *result, size_t result_length,
-                  const uint8_t *data, size_t length);
-
-}
-
-#endif  // OTS_WOFF2_H_
diff --git a/lib/eotconverter.jar b/lib/eotconverter.jar
deleted file mode 100644
index 6543d70..0000000
--- a/lib/eotconverter.jar
+++ /dev/null
Binary files differ
diff --git a/lib/guava-11.0.1.jar b/lib/guava-11.0.1.jar
deleted file mode 100644
index af4a383..0000000
--- a/lib/guava-11.0.1.jar
+++ /dev/null
Binary files differ
diff --git a/lib/lzma.jar b/lib/lzma.jar
deleted file mode 100644
index 29a44e3..0000000
--- a/lib/lzma.jar
+++ /dev/null
Binary files differ
diff --git a/lib/sfntly.jar b/lib/sfntly.jar
deleted file mode 100644
index 415d5c5..0000000
--- a/lib/sfntly.jar
+++ /dev/null
Binary files differ
diff --git a/lib/woffconverter.jar b/lib/woffconverter.jar
deleted file mode 100644
index 1ac0133..0000000
--- a/lib/woffconverter.jar
+++ /dev/null
Binary files differ
diff --git a/src/com/google/typography/font/compression/AdvWidth.java b/src/com/google/typography/font/compression/AdvWidth.java
deleted file mode 100644
index 5bf67b5..0000000
--- a/src/com/google/typography/font/compression/AdvWidth.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.google.typography.font.compression;
-
-import com.google.typography.font.sfntly.Font;
-import com.google.typography.font.sfntly.Tag;
-import com.google.typography.font.sfntly.data.WritableFontData;
-import com.google.typography.font.sfntly.table.core.HorizontalMetricsTable;
-
-/**
- * Extract just advance widths from hmtx table.
- *
- * @author Raph Levien
- */
-public class AdvWidth {
-
-  public static WritableFontData encode(Font font) {
-    HorizontalMetricsTable hmtx = font.getTable(Tag.hmtx);
-    int nMetrics = hmtx.numberOfHMetrics();
-    WritableFontData result = WritableFontData.createWritableFontData(nMetrics * 2);
-    for (int i = 0; i < nMetrics; i++) {
-      result.writeShort(i * 2, hmtx.hMetricAdvanceWidth(i));
-    }
-    return result;
-  }
-}
diff --git a/src/com/google/typography/font/compression/CmapEncoder.java b/src/com/google/typography/font/compression/CmapEncoder.java
deleted file mode 100644
index 64888d6..0000000
--- a/src/com/google/typography/font/compression/CmapEncoder.java
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.google.typography.font.compression;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.typography.font.sfntly.Font;
-import com.google.typography.font.sfntly.Tag;
-import com.google.typography.font.sfntly.table.core.CMap;
-import com.google.typography.font.sfntly.table.core.CMapTable;
-import com.google.typography.font.sfntly.table.core.MaximumProfileTable;
-
-import java.io.ByteArrayOutputStream;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Experimental CMap encoder, based primarily on writing the _inverse_ encoding.
- *
- * @author Raph Levien
- */
-public class CmapEncoder {
-
-  public static byte[] encode(Font font) {
-    int nGlyphs = font.<MaximumProfileTable>getTable(Tag.maxp).numGlyphs();
-    CMapTable cmapTable = font.getTable(Tag.cmap);
-    CMap cmap = getBestCMap(cmapTable);
-    Map<Integer, Integer> invEncoding = Maps.newHashMap();
-    List<Integer> exceptions = Lists.newArrayList();
-    for (Integer i : cmap) {
-      int glyphId = cmap.glyphId(i);
-      if (invEncoding.containsKey(glyphId)) {
-        exceptions.add(i);
-        exceptions.add(glyphId);
-      } else {
-        invEncoding.put(glyphId, i);
-      }
-    }
-    ByteArrayOutputStream os = new ByteArrayOutputStream();
-    int last = -1;
-    for (int i = 0; i < nGlyphs; i++) {
-      if (invEncoding.containsKey(i)) {
-        int value = invEncoding.get(i);
-        int delta = value - last;
-        writeVShort(os, delta);
-        last = value;
-      } else {
-        writeVShort(os, 0);
-      }
-    }
-    for (int i : exceptions) {
-      writeVShort(os, i);
-    }
-    return os.toByteArray();
-  }
-
-  private static CMap getBestCMap(CMapTable cmapTable) {
-    for (CMap cmap : cmapTable) {
-      if (cmap.format() == CMap.CMapFormat.Format12.value()) {
-        return cmap;
-      }
-    }
-    for (CMap cmap : cmapTable) {
-      if (cmap.format() == CMap.CMapFormat.Format4.value()) {
-        return cmap;
-      }
-    }
-    return null;
-  }
-
-  // A simple signed varint encoding
-  static void writeVShort(ByteArrayOutputStream os, int value) {
-    if (value >= 0x2000 || value < -0x2000) {
-      os.write((byte)(0x80 | ((value >> 14) & 0x7f)));
-    }
-    if (value >= 0x40 || value < -0x40) {
-      os.write((byte)(0x80 | ((value >> 7) & 0x7f)));
-    }
-    os.write((byte)(value & 0x7f));
-  }
-}
diff --git a/src/com/google/typography/font/compression/CompressLzma.java b/src/com/google/typography/font/compression/CompressLzma.java
deleted file mode 100644
index 4bda54c..0000000
--- a/src/com/google/typography/font/compression/CompressLzma.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
-
-package com.google.typography.font.compression;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import SevenZip.Compression.LZMA.Encoder;
-
-/**
- * @author Raph Levien
- * @author David Kuettel
- */
-public class CompressLzma {
-
-  public static byte[] compress(byte[] input) {
-    try {
-      ByteArrayInputStream in = new ByteArrayInputStream(input);
-      ByteArrayOutputStream out = new ByteArrayOutputStream();
-
-      Encoder encoder = new Encoder();
-      encoder.SetAlgorithm(2);
-      encoder.SetDictionarySize(1 << 23);
-      encoder.SetNumFastBytes(128);
-      encoder.SetMatchFinder(1);
-      encoder.SetLcLpPb(3, 0, 2);
-      encoder.SetEndMarkerMode(true);
-      encoder.WriteCoderProperties(out);
-      for (int i = 0; i < 8; i++) {
-        out.write((int) ((long) -1 >>> (8 * i)) & 0xFF);
-      }
-      encoder.Code(in, out, -1, -1, null);
-
-      out.flush();
-      out.close();
-
-      return out.toByteArray();
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
-}
diff --git a/src/com/google/typography/font/compression/CompressionRunner.java b/src/com/google/typography/font/compression/CompressionRunner.java
deleted file mode 100644
index 75d6370..0000000
--- a/src/com/google/typography/font/compression/CompressionRunner.java
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.google.typography.font.compression;
-
-import com.google.common.collect.Lists;
-import com.google.common.io.Files;
-import com.google.typography.font.sfntly.Font;
-import com.google.typography.font.sfntly.FontFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.List;
-
-/**
- * A command-line tool for running different experimental compression code over
- * a corpus of fonts, and gathering statistics, particularly compression
- * efficiency.
- *
- * This is not intended to be production code.
- *
- * @author Raph Levien
- */
-public class CompressionRunner {
-
-  public static void main(String[] args) throws IOException {
-    boolean generateOutput = false;
-    List<String> descs = Lists.newArrayList();
-    String baseline = "gzip";
-
-    List<String> filenames = Lists.newArrayList();
-    for (int i = 0; i < args.length; i++) {
-      if (args[i].charAt(0) == '-') {
-        if (args[i].equals("-o")) {
-          generateOutput = true;
-        } else if (args[i].equals("-x")) {
-          descs.add(args[i + 1]);
-          i++;
-        } else if (args[i].equals("-b")) {
-          baseline = args[i + 1];
-          i++;
-        }
-      } else {
-        filenames.add(args[i]);
-      }
-    }
-
-    // String baseline = "glyf/triplet,code,push:lzma";
-    // String baseline = "glyf/cbbox,triplet,code,push:hdmx:lzma";
-    // descs.add("woff2");
-    if (descs.isEmpty()) {
-      descs.add("glyf/cbbox,triplet,code,reslice:woff2/lzma");
-    }
-    run(filenames, baseline, descs, generateOutput);
-  }
-
-  private static void run(List<String> filenames, String baseline, List<String> descs,
-                          boolean generateOutput) throws IOException {
-    PrintWriter o = new PrintWriter(System.out);
-    List<StatsCollector> stats = Lists.newArrayList();
-    for (int i = 0; i < descs.size(); i++) {
-      stats.add(new StatsCollector());
-    }
-    FontFactory fontFactory = FontFactory.getInstance();
-    o.println("<html>");
-    for (String filename : filenames) {
-      byte[] bytes = Files.toByteArray(new File(filename));
-      Font font = fontFactory.loadFonts(bytes)[0];
-      byte[] baselineResult = Experiment.run(font, baseline);
-      o.printf("<!-- %s: baseline %d bytes", new File(filename).getName(), baselineResult.length);
-      for (int i = 0; i < descs.size(); i++) {
-        byte[] expResult = Experiment.run(font, descs.get(i));
-        if (generateOutput) {
-          String newFilename = filename;
-          if (newFilename.endsWith(".ttf")) {
-            newFilename = newFilename.substring(0, newFilename.length() - 4);
-          }
-          newFilename += ".woff2";
-          Files.write(expResult, new File(newFilename));
-        }
-        double percent = 100. * expResult.length / baselineResult.length;
-        stats.get(i).addStat(percent);
-        o.printf(", %c %.2f%%", 'A' + i, percent);
-      }
-      o.printf(" -->\n");
-    }
-    stats.get(0).chartHeader(o, descs.size());
-    for (int i = 0; i < descs.size(); i++) {
-      stats.get(i).chartData(o, i + 1);
-    }
-    stats.get(0).chartEnd(o);
-    o.printf("<p>baseline: %s</p>\n", baseline);
-    for (int i = 0; i < descs.size(); i++) {
-      StatsCollector sc = stats.get(i);
-      o.printf("<p>%c: %s: median %f, mean %f</p>\n",
-          'A' + i, descs.get(i), sc.median(), sc.mean());
-    }
-    stats.get(0).chartFooter(o);
-    o.close();
-  }
-}
diff --git a/src/com/google/typography/font/compression/CompressionStats.java b/src/com/google/typography/font/compression/CompressionStats.java
deleted file mode 100644
index 9b5caee..0000000
--- a/src/com/google/typography/font/compression/CompressionStats.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.google.typography.font.compression;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Compression stats, both aggregate and per font.
- *
- * @author David Kuettel
- */
-public class CompressionStats {
-
-  public enum Size { ORIGINAL, GZIP, WOFF, WOFF2 }
-
-  private final List<Stats> values = Lists.newArrayList();
-
-  public void add(Stats stat) {
-    values.add(stat);
-  }
-
-  public List<Stats> values() {
-    return values;
-  }
-
-  public double mean(Size size) {
-    double sum = 0;
-    for (Long value : values(size)) {
-      sum += value;
-    }
-    return sum / values.size();
-  }
-
-  public double median(Size size) {
-    List<Long> list = values(size);
-    Collections.sort(list);
-    int length = list.size();
-    if (length % 2 == 1) {
-      return list.get((length - 1) / 2);
-    } else {
-      return 0.5 * (list.get(length / 2 - 1) + list.get(length / 2));
-    }
-  }
-
-  private List<Long> values(Size size) {
-    List<Long> list = Lists.newArrayList();
-    for (Stats stats : values) {
-      list.add(stats.getSize(size));
-    }
-    return list;
-  }
-
-  public static class Stats {
-
-    private final String filename;
-    private final Map<Size, Long> sizes;
-
-    private Stats(String filename, Map<Size, Long> sizes) {
-      this.filename = filename;
-      this.sizes = sizes;
-    }
-
-    public String getFilename() {
-      return filename;
-    }
-
-    public long getSize(Size size) {
-      return sizes.get(size);
-    }
-
-    public double getPercent(Size s1, Size s2) {
-      long v1 = sizes.get(s1);
-      long v2 = sizes.get(s2);
-      return 100.0 * (v1 - v2) / v1;
-    }
-
-    public static Builder builder() {
-      return new Builder();
-    }
-
-    public static class Builder {
-
-      private String filename;
-      private Map<Size, Long> sizes = Maps.newHashMap();
-
-      public Builder setFilename(String filename) {
-        this.filename = filename;
-        return this;
-      }
-
-      public Builder setSize(Size key, long value) {
-        this.sizes.put(key, value);
-        return this;
-      }
-
-      public Stats build() {
-        return new Stats(filename, ImmutableMap.copyOf(sizes));
-      }
-    }
-  }
-}
diff --git a/src/com/google/typography/font/compression/CsvReport.java b/src/com/google/typography/font/compression/CsvReport.java
deleted file mode 100644
index 4125a23..0000000
--- a/src/com/google/typography/font/compression/CsvReport.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.google.typography.font.compression;
-
-import com.google.common.io.Closeables;
-
-import java.io.BufferedWriter;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-
-/**
- * Generates a CSV report containing the compression stats.
- *
- * @author David Kuettel
- */
-public class CsvReport {
-
-  public static void create(CompressionStats stats, String filename) throws IOException {
-    PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(filename)));
-    try {
-      writer.printf("Font, Original (bytes), WOFF 1.0 (bytes), WOFF 2.0 (bytes), %% Improvement\n");
-      for (CompressionStats.Stats stat : stats.values()) {
-        writer.printf("%s, %d, %d, %d, %.2f%%\n",
-            stat.getFilename(),
-            stat.getSize(CompressionStats.Size.ORIGINAL),
-            stat.getSize(CompressionStats.Size.WOFF),
-            stat.getSize(CompressionStats.Size.WOFF2),
-            stat.getPercent(CompressionStats.Size.WOFF, CompressionStats.Size.WOFF2));
-      }
-    } finally {
-      Closeables.closeQuietly(writer);
-    }
-  }
-}
diff --git a/src/com/google/typography/font/compression/Experiment.java b/src/com/google/typography/font/compression/Experiment.java
deleted file mode 100644
index a5e97e9..0000000
--- a/src/com/google/typography/font/compression/Experiment.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.google.typography.font.compression;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import com.google.typography.font.sfntly.Font;
-import com.google.typography.font.sfntly.FontFactory;
-import com.google.typography.font.sfntly.Tag;
-import com.google.typography.font.tools.conversion.eot.EOTWriter;
-import com.google.typography.font.tools.conversion.woff.WoffWriter;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * @author Raph Levien
- */
-public class Experiment {
-
-  /**
-   * Does one experimental compression on a font, using the string to guide what
-   * gets done.
-   *
-   * @param srcFont Source font
-   * @param desc experiment description string; the exact format is probably
-   *        still evolving
-   * @return serialization of compressed font
-   * @throws IOException
-   */
-  public static byte[] run(Font srcFont, String desc) throws IOException {
-    Font font = srcFont;
-    FontFactory fontFactory = FontFactory.getInstance();
-    String[] pieces = desc.split(":");
-    boolean keepDsig = false;
-
-    for (int i = 0; i < pieces.length - 1; i++) {
-      String[] piece = pieces[i].split("/");
-      String cmd = piece[0];
-      if (cmd.equals("glyf")) {
-        font = FontUtil.preprocessMtxGlyf(font, piece.length > 1 ? piece[1] : "").build();
-      } else if (cmd.equals("hmtx")) {
-        font = FontUtil.preprocessHmtx(font).build();
-      } else if (cmd.equals("hdmx")) {
-        font = FontUtil.preprocessHdmx(font).build();
-      } else if (cmd.equals("cmap")) {
-        font = FontUtil.preprocessCmap(font).build();
-      } else if (cmd.equals("kern")) {
-        font = FontUtil.preprocessKern(font).build();
-      } else if (cmd.equals("keepdsig")) {
-        keepDsig = true;
-      } else if (cmd.equals("strip")) {
-        Set<Integer> removeTags = Sets.newTreeSet();
-        for (String tag : piece[1].split(",")) {
-          removeTags.add(Tag.intValue(tag.getBytes()));
-        }
-        font = FontUtil.stripTags(font, removeTags).build();
-      }
-    }
-    if (!keepDsig) {
-      font = FontUtil.stripTags(font, ImmutableSet.of(Tag.DSIG)).build();
-    }
-
-    String last = pieces[pieces.length - 1];
-    String[] lastPieces = last.split("/");
-    String lastBase = lastPieces[0];
-    String lastArgs = lastPieces.length > 1 ? lastPieces[1] : "";
-    if (!lastBase.equals("woff2")) {
-      Set<Integer> tagsToStrip = Sets.newHashSet();
-      for (Map.Entry<Integer, Integer> mapping : Woff2Writer.getTransformMap().entrySet()) {
-        if (font.hasTable(mapping.getValue())) {
-          tagsToStrip.add(mapping.getKey());
-        }
-      }
-      font = FontUtil.stripTags(font, tagsToStrip).build();
-    }
-
-    byte[] result = null;
-    if (lastBase.equals("gzip")) {
-      result = GzipUtil.deflate(FontUtil.toBytes(fontFactory, font));
-    } else if (lastBase.equals("lzma")) {
-      result = CompressLzma.compress(FontUtil.toBytes(fontFactory, font));
-    } else if (lastBase.equals("woff")) {
-      result = FontUtil.toBytes(new WoffWriter().convert(font));
-    } else if (lastBase.equals("woff2")) {
-      result = FontUtil.toBytes(new Woff2Writer(lastArgs).convert(font));
-    } else if (lastBase.equals("eot")) {
-      result = FontUtil.toBytes(new EOTWriter(true).convert(font));
-    } else if (lastBase.equals("uncomp")) {
-      result = FontUtil.toBytes(fontFactory, font);
-    }
-    return result;
-  }
-}
diff --git a/src/com/google/typography/font/compression/FontUtil.java b/src/com/google/typography/font/compression/FontUtil.java
deleted file mode 100644
index 155a042..0000000
--- a/src/com/google/typography/font/compression/FontUtil.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.google.typography.font.compression;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.typography.font.sfntly.Font;
-import com.google.typography.font.sfntly.FontFactory;
-import com.google.typography.font.sfntly.Tag;
-import com.google.typography.font.sfntly.data.ReadableFontData;
-import com.google.typography.font.tools.conversion.eot.HdmxEncoder;
-
-import java.io.ByteArrayOutputStream;
-import java.util.Arrays;
-import java.util.Set;
-
-/**
- * Font utility methods
- *
- * @author Raph Levien
- */
-public class FontUtil {
-
-  public static Font.Builder stripTags(Font srcFont, Set<Integer> removeTags) {
-    FontFactory fontFactory = FontFactory.getInstance();
-    Font.Builder fontBuilder = fontFactory.newFontBuilder();
-
-    for (Integer tag : srcFont.tableMap().keySet()) {
-      if (!removeTags.contains(tag)) {
-        fontBuilder.newTableBuilder(tag, srcFont.getTable(tag).readFontData());
-      }
-    }
-    return fontBuilder;
-  }
-
-  public static Font.Builder preprocessMtxGlyf(Font srcFont, String options) {
-    Font.Builder fontBuilder = stripTags(srcFont, ImmutableSet.<Integer>of());
-    GlyfEncoder glyfEncoder = new GlyfEncoder(options);
-    glyfEncoder.encode(srcFont);
-    addTableBytes(fontBuilder, Tag.intValue(new byte[]{'g', 'l', 'z', '1'}),
-        glyfEncoder.getGlyfBytes());
-    addTableBytes(fontBuilder, Tag.intValue(new byte[] {'l', 'o', 'c', 'z'}),
-        glyfEncoder.getLocaBytes());
-    if (!Arrays.asList(options.split(",")).contains("reslice")) {
-      addTableBytes(fontBuilder, Tag.intValue(new byte[] {'g', 'l', 'z', '2'}),
-          glyfEncoder.getCodeBytes());
-      addTableBytes(fontBuilder, Tag.intValue(new byte[] {'g', 'l', 'z', '3'}),
-          glyfEncoder.getPushBytes());
-    }
-    return fontBuilder;
-  }
-
-  public static Font.Builder preprocessHmtx(Font srcFont) {
-    Font.Builder fontBuilder = stripTags(srcFont, ImmutableSet.of(Tag.hmtx));
-    addTableBytes(fontBuilder, Tag.intValue(new byte[] {'h', 'm', 't', 'z'}),
-        toBytes(AdvWidth.encode(srcFont)));
-    return fontBuilder;
-  }
-
-  public static Font.Builder preprocessHdmx(Font srcFont) {
-    Font.Builder fontBuilder = stripTags(srcFont, ImmutableSet.of(Tag.hdmx));
-    if (srcFont.hasTable(Tag.hdmx)) {
-      addTableBytes(fontBuilder, Tag.hdmx, toBytes(new HdmxEncoder().encode(srcFont)));
-    }
-    return fontBuilder;
-  }
-
-  public static Font.Builder preprocessCmap(Font srcFont) {
-    Font.Builder fontBuilder = stripTags(srcFont, ImmutableSet.of(Tag.cmap));
-    addTableBytes(fontBuilder, Tag.intValue(new byte[] {'c', 'm', 'a', 'z'}),
-        CmapEncoder.encode(srcFont));
-    return fontBuilder;
-  }
-
-  public static Font.Builder preprocessKern(Font srcFont) {
-    Font.Builder fontBuilder = stripTags(srcFont, ImmutableSet.of(Tag.kern));
-    if (srcFont.hasTable(Tag.kern)) {
-      addTableBytes(fontBuilder, Tag.intValue(new byte[] {'k', 'e', 'r', 'z'}),
-          toBytes(KernEncoder.encode(srcFont)));
-    }
-    return fontBuilder;
-  }
-
-  public static void addTableBytes(Font.Builder fontBuilder, int tag, byte[] contents) {
-    fontBuilder.newTableBuilder(tag, ReadableFontData.createReadableFontData(contents));
-  }
-
-  public static byte[] toBytes(FontFactory fontFactory, Font font) {
-    try {
-      ByteArrayOutputStream baos = new ByteArrayOutputStream();
-      fontFactory.serializeFont(font, baos);
-      return baos.toByteArray();
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  public static byte[] toBytes(ReadableFontData rfd) {
-    byte[] result = new byte[rfd.length()];
-    rfd.readBytes(0, result, 0, rfd.length());
-    return result;
-  }
-}
diff --git a/src/com/google/typography/font/compression/GlyfEncoder.java b/src/com/google/typography/font/compression/GlyfEncoder.java
deleted file mode 100644
index 1144ee1..0000000
--- a/src/com/google/typography/font/compression/GlyfEncoder.java
+++ /dev/null
@@ -1,481 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.google.typography.font.compression;
-
-import com.google.typography.font.sfntly.Font;
-import com.google.typography.font.sfntly.Tag;
-import com.google.typography.font.sfntly.data.ReadableFontData;
-import com.google.typography.font.sfntly.table.core.FontHeaderTable;
-import com.google.typography.font.sfntly.table.truetype.CompositeGlyph;
-import com.google.typography.font.sfntly.table.truetype.Glyph;
-import com.google.typography.font.sfntly.table.truetype.GlyphTable;
-import com.google.typography.font.sfntly.table.truetype.LocaTable;
-import com.google.typography.font.sfntly.table.truetype.SimpleGlyph;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Implementation of compression of CTF glyph data, as per sections 5.6-5.10 and 6 of the spec.
- * This is a hacked-up version with a number of options, for experimenting.
- *
- * @author Raph Levien
- */
-public class GlyfEncoder {
-
-  private final ByteArrayOutputStream nContourStream;
-  private final ByteArrayOutputStream nPointsStream;
-  private final ByteArrayOutputStream flagBytesStream;
-  private final ByteArrayOutputStream compositeStream;
-  private final ByteArrayOutputStream bboxStream;
-  private final ByteArrayOutputStream glyfStream;
-  private final ByteArrayOutputStream pushStream;
-  private final ByteArrayOutputStream codeStream;
-  private final boolean sbbox;
-  private final boolean cbbox;
-  private final boolean code;
-  private final boolean triplet;
-  private final boolean doPush;
-  private final boolean doHop;
-  private final boolean push2byte;
-  private final boolean reslice;
-
-  private int nGlyphs;
-  private byte[] bboxBitmap;
-  private FontHeaderTable.IndexToLocFormat indexFmt;
-
-  public GlyfEncoder(String options) {
-    glyfStream = new ByteArrayOutputStream();
-    pushStream = new ByteArrayOutputStream();
-    codeStream = new ByteArrayOutputStream();
-    nContourStream = new ByteArrayOutputStream();
-    nPointsStream = new ByteArrayOutputStream();
-    flagBytesStream = new ByteArrayOutputStream();
-    compositeStream = new ByteArrayOutputStream();
-    bboxStream = new ByteArrayOutputStream();
-    boolean sbbox = false;
-    boolean cbbox = false;
-    boolean code = false;
-    boolean triplet = false;
-    boolean doPush = false;
-    boolean reslice = false;
-    boolean doHop = false;
-    boolean push2byte = false;
-    for (String option : options.split(",")) {
-      if (option.equals("sbbox")) {
-        sbbox = true;
-      } else if (option.equals("cbbox")) {
-        cbbox = true;
-      } else if (option.equals("code")) {
-        code = true;
-      } else if (option.equals("triplet")) {
-        triplet = true;
-      } else if (option.equals("push")) {
-        doPush = true;
-      } else if (option.equals("hop")) {
-        doHop = true;
-      } else if (option.equals("push2byte")) {
-        push2byte = true;
-      } else if (option.equals("reslice")) {
-        reslice = true;
-      }
-    }
-    this.sbbox = sbbox;
-    this.cbbox = cbbox;
-    this.code = code;
-    this.triplet = triplet;
-    this.doPush = doPush;
-    this.doHop = doHop;
-    this.push2byte = push2byte;
-    this.reslice = reslice;
-  }
-
-  public void encode(Font sourceFont) {
-    FontHeaderTable head = sourceFont.getTable(Tag.head);
-    indexFmt = head.indexToLocFormat();
-    LocaTable loca = sourceFont.getTable(Tag.loca);
-    nGlyphs = loca.numGlyphs();
-    GlyphTable glyf = sourceFont.getTable(Tag.glyf);
-    bboxBitmap = new byte[((nGlyphs + 31) >> 5) << 2];
-
-    for (int glyphId = 0; glyphId < nGlyphs; glyphId++) {
-      int sourceOffset = loca.glyphOffset(glyphId);
-      int length = loca.glyphLength(glyphId);
-      Glyph glyph = glyf.glyph(sourceOffset, length);
-      writeGlyph(glyphId, glyph);
-    }
-  }
-
-  private void writeGlyph(int glyphId, Glyph glyph) {
-    try {
-      if (glyph == null || glyph.dataLength() == 0) {
-        writeNContours(0);
-      } else if (glyph instanceof SimpleGlyph) {
-        writeSimpleGlyph(glyphId, (SimpleGlyph)glyph);
-      } else if (glyph instanceof CompositeGlyph) {
-        writeCompositeGlyph(glyphId, (CompositeGlyph)glyph);
-      }
-    } catch (IOException e) {
-      throw new RuntimeException("unexpected IOException writing glyph data", e);
-    }
-  }
-
-  private void writeInstructions(Glyph glyph) throws IOException{
-    if (doPush) {
-      splitPush(glyph);
-    } else {
-      int pushCount = 0;
-      int codeSize = glyph.instructionSize();
-      if (!reslice) {
-        write255UShort(glyfStream, pushCount);
-      }
-      write255UShort(glyfStream, codeSize);
-      if (codeSize > 0) {
-        if (code) {
-          glyph.instructions().copyTo(codeStream);
-        } else {
-          glyph.instructions().copyTo(glyfStream);
-        }
-      }
-    }
-  }
-
-  private void writeSimpleGlyph(int glyphId, SimpleGlyph glyph) throws IOException {
-    int numContours = glyph.numberOfContours();
-    writeNContours(numContours);
-    if (sbbox) {
-      writeBbox(glyphId, glyph);
-    }
-    // TODO: check that bbox matches, write bbox if not
-    for (int i = 0; i < numContours; i++) {
-      if (reslice) {
-        write255UShort(nPointsStream, glyph.numberOfPoints(i));
-      } else {
-        write255UShort(glyfStream, glyph.numberOfPoints(i) - (i == 0 ? 1 : 0));
-      }
-    }
-    ByteArrayOutputStream os = new ByteArrayOutputStream();
-    int lastX = 0;
-    int lastY = 0;
-    for (int i = 0; i < numContours; i++) {
-      int numPoints = glyph.numberOfPoints(i);
-      for (int j = 0; j < numPoints; j++) {
-        int x = glyph.xCoordinate(i, j);
-        int y = glyph.yCoordinate(i, j);
-        int dx = x - lastX;
-        int dy = y - lastY;
-        if (triplet) {
-          writeTriplet(os, glyph.onCurve(i, j), dx, dy);
-        } else {
-          writeVShort(os, dx * 2 + (glyph.onCurve(i, j) ? 1 : 0));
-          writeVShort(os, dy);
-        }
-        lastX = x;
-        lastY = y;
-      }
-    }
-    os.writeTo(glyfStream);
-    if (numContours > 0) {
-      writeInstructions(glyph);
-    }
-  }
-
-  private void writeCompositeGlyph(int glyphId, CompositeGlyph glyph) throws IOException {
-    boolean haveInstructions = false;
-    writeNContours(-1);
-    if (cbbox) {
-      writeBbox(glyphId, glyph);
-    }
-    ByteArrayOutputStream outStream = reslice ? compositeStream : glyfStream;
-    for (int i = 0; i < glyph.numGlyphs(); i++) {
-      int flags = glyph.flags(i);
-      writeUShort(outStream, flags);
-      haveInstructions = (flags & CompositeGlyph.FLAG_WE_HAVE_INSTRUCTIONS) != 0;
-      writeUShort(outStream, glyph.glyphIndex(i));
-      if ((flags & CompositeGlyph.FLAG_ARG_1_AND_2_ARE_WORDS) == 0) {
-        outStream.write(glyph.argument1(i));
-        outStream.write(glyph.argument2(i));
-      } else {
-        writeUShort(outStream, glyph.argument1(i));
-        writeUShort(outStream, glyph.argument2(i));
-      }
-      if (glyph.transformationSize(i) != 0) {
-        try {
-          outStream.write(glyph.transformation(i));
-        } catch (IOException e) {
-        }
-      }
-    }
-    if (haveInstructions) {
-      writeInstructions(glyph);
-    }
-  }
-
-  private void writeNContours(int nContours) {
-    if (reslice) {
-      writeUShort(nContourStream, nContours);
-    } else {
-      writeUShort(nContours);
-    }
-  }
-
-  private void writeBbox(int glyphId, Glyph glyph) {
-    if (reslice) {
-      bboxBitmap[glyphId >> 3] |= 0x80 >> (glyphId & 7);
-    }
-    ByteArrayOutputStream outStream = reslice ? bboxStream : glyfStream;
-    writeUShort(outStream, glyph.xMin());
-    writeUShort(outStream, glyph.yMin());
-    writeUShort(outStream, glyph.xMax());
-    writeUShort(outStream, glyph.yMax());
-  }
-
-  private void writeUShort(ByteArrayOutputStream os, int value) {
-    os.write(value >> 8);
-    os.write(value & 255);
-  }
-
-  private void writeUShort(int value) {
-    writeUShort(glyfStream, value);
-  }
-
-  private void writeLong(OutputStream os, int value) throws IOException {
-    os.write((value >> 24) & 255);
-    os.write((value >> 16) & 255);
-    os.write((value >> 8) & 255);
-    os.write(value & 255);
-  }
-
-  // As per 6.1.1 of spec
-  // visible for testing
-  static void write255UShort(ByteArrayOutputStream os, int value) {
-    if (value < 0) {
-      throw new IllegalArgumentException();
-    }
-    if (value < 253) {
-      os.write((byte)value);
-    } else if (value < 506) {
-      os.write(255);
-      os.write((byte)(value - 253));
-    } else if (value < 762) {
-      os.write(254);
-      os.write((byte)(value - 506));
-    } else {
-      os.write(253);
-      os.write((byte)(value >> 8));
-      os.write((byte)(value & 0xff));
-    }
-  }
-
-  // As per 6.1.1 of spec
-  // visible for testing
-  static void write255Short(OutputStream os, int value) throws IOException {
-    int absValue = Math.abs(value);
-    if (value < 0) {
-      // spec is unclear about whether words should be signed. This code is conservative, but we
-      // can test once the implementation is working.
-      os.write(250);
-    }
-    if (absValue < 250) {
-      os.write((byte)absValue);
-    } else if (absValue < 500) {
-      os.write(255);
-      os.write((byte)(absValue - 250));
-    } else if (absValue < 756) {
-      os.write(254);
-      os.write((byte)(absValue - 500));
-    } else {
-      os.write(253);
-      os.write((byte)(absValue >> 8));
-      os.write((byte)(absValue & 0xff));
-    }
-  }
-
-  // A simple signed varint encoding
-  static void writeVShort(ByteArrayOutputStream os, int value) {
-    if (value >= 0x2000 || value < -0x2000) {
-      os.write((byte)(0x80 | ((value >> 14) & 0x7f)));
-    }
-    if (value >= 0x40 || value < -0x40) {
-      os.write((byte)(0x80 | ((value >> 7) & 0x7f)));
-    }
-    os.write((byte)(value & 0x7f));
-  }
-
-  // As in section 5.11 of the spec
-  // visible for testing
-  void writeTriplet(OutputStream os, boolean onCurve, int x, int y) throws IOException {
-    int absX = Math.abs(x);
-    int absY = Math.abs(y);
-    int onCurveBit = onCurve ? 0 : 128;
-    int xSignBit = (x < 0) ? 0 : 1;
-    int ySignBit = (y < 0) ? 0 : 1;
-    int xySignBits = xSignBit + 2 * ySignBit;
-    ByteArrayOutputStream flagStream = reslice ? flagBytesStream : glyfStream;
-
-    if (x == 0 && absY < 1280) {
-      flagStream.write(onCurveBit + ((absY & 0xf00) >> 7) + ySignBit);
-      os.write(absY & 0xff);
-    } else if (y == 0 && absX < 1280) {
-      flagStream.write(onCurveBit + 10 + ((absX & 0xf00) >> 7) + xSignBit);
-      os.write(absX & 0xff);
-    } else if (absX < 65 && absY < 65) {
-      flagStream.write(onCurveBit + 20 + ((absX - 1) & 0x30) + (((absY - 1) & 0x30) >> 2) +
-          xySignBits);
-      os.write((((absX - 1) & 0xf) << 4) | ((absY - 1) & 0xf));
-    } else if (absX < 769 && absY < 769) {
-      flagStream.write(onCurveBit + 84 + 12 * (((absX - 1) & 0x300) >> 8) +
-          (((absY - 1) & 0x300) >> 6) + xySignBits);
-      os.write((absX - 1) & 0xff);
-      os.write((absY - 1) & 0xff);
-    } else if (absX < 4096 && absY < 4096) {
-      flagStream.write(onCurveBit + 120 + xySignBits);
-      os.write(absX >> 4);
-      os.write(((absX & 0xf) << 4) | (absY >> 8));
-      os.write(absY & 0xff);
-    } else {
-      flagStream.write(onCurveBit + 124 + xySignBits);
-      os.write(absX >> 8);
-      os.write(absX & 0xff);
-      os.write(absY >> 8);
-      os.write(absY & 0xff);
-    }
-  }
-
-  /**
-   * Split the instructions into a push sequence and the remainder of the instructions.
-   * Writes both streams, and the counts to the glyfStream.
-   *
-   * @param glyph
-   */
-  private void splitPush(Glyph glyph) throws IOException {
-    int instrSize = glyph.instructionSize();
-    ReadableFontData data = glyph.instructions();
-    int i = 0;
-    List<Integer> result = new ArrayList<Integer>();
-    // All push sequences are at least two bytes, make sure there's enough room
-    while (i + 1 < instrSize) {
-      int ix = i;
-      int instr = data.readUByte(ix++);
-      int n = 0;
-      int size = 0;
-      if (instr == 0x40 || instr == 0x41) {
-        // NPUSHB, NPUSHW
-        n = data.readUByte(ix++);
-        size = (instr & 1) + 1;
-      } else if (instr >= 0xB0 && instr < 0xC0) {
-        // PUSHB, PUSHW
-        n = 1 + (instr & 7);
-        size = ((instr & 8) >> 3) + 1;
-      } else {
-        break;
-      }
-      if (i + size * n > instrSize) {
-        // This is a broken font, and a potential buffer overflow, but in the interest
-        // of preserving the original, we just put the broken instruction sequence in
-        // the stream.
-        break;
-      }
-      for (int j = 0; j < n; j++) {
-        if (size == 1) {
-          result.add(data.readUByte(ix));
-        } else {
-          result.add(data.readShort(ix));
-        }
-        ix += size;
-      }
-      i = ix;
-    }
-    int pushCount = result.size();
-    int codeSize = instrSize - i;
-    write255UShort(glyfStream, pushCount);
-    write255UShort(glyfStream, codeSize);
-    encodePushSequence(pushStream, result);
-    if (codeSize > 0) {
-      data.slice(i).copyTo(codeStream);
-    }
-  }
-
-  // As per section 6.2.2 of the spec
-  private void encodePushSequence(ByteArrayOutputStream os, List<Integer> data) throws IOException {
-    int n = data.size();
-    int hopSkip = 0;
-    for (int i = 0; i < n; i++) {
-      if ((hopSkip & 1) == 0) {
-        int val = data.get(i);
-        if (doHop && hopSkip == 0 && i >= 2 &&
-            i + 2 < n && val == data.get(i - 2) && val == data.get(i + 2)) {
-          if (i + 4 < n && val == data.get(i + 4)) {
-            // Hop4 code
-            os.write(252);
-            hopSkip = 0x14;
-          } else {
-            // Hop3 code
-            os.write(251);
-            hopSkip = 4;
-          }
-        } else {
-          if (push2byte) {
-            // Measure relative effectiveness of 255Short literal encoding vs 2-byte ushort.
-            writeUShort(os, data.get(i));
-          } else {
-            write255Short(os, data.get(i));
-          }
-        }
-      }
-      hopSkip >>= 1;
-    }
-  }
-
-  public byte[] getGlyfBytes() {
-    if (reslice) {
-      ByteArrayOutputStream newStream = new ByteArrayOutputStream();
-      try {
-        // Pack all the glyf streams in a sensible way
-        writeLong(newStream, 0);  // version
-        writeUShort(newStream, nGlyphs);
-        writeUShort(newStream, indexFmt.value());
-        writeLong(newStream, nContourStream.size());
-        writeLong(newStream, nPointsStream.size());
-        writeLong(newStream, flagBytesStream.size());
-        writeLong(newStream, glyfStream.size());
-        writeLong(newStream, compositeStream.size());
-        writeLong(newStream, bboxBitmap.length + bboxStream.size());
-        writeLong(newStream, codeStream.size());
-//        System.out.printf("stream sizes = %d %d %d %d %d %d %d\n",
-//            nContourStream.size(), nPointsStream.size(), flagBytesStream.size(), glyfStream.size(),
-//            compositeStream.size(), bboxStream.size(), codeStream.size());
-        nContourStream.writeTo(newStream);
-        nPointsStream.writeTo(newStream);
-        flagBytesStream.writeTo(newStream);
-        glyfStream.writeTo(newStream);
-        compositeStream.writeTo(newStream);
-        newStream.write(bboxBitmap);
-        bboxStream.writeTo(newStream);
-        codeStream.writeTo(newStream);
-      } catch (IOException e) {
-        throw new RuntimeException("Can't happen, world must have come to end", e);
-      }
-      return newStream.toByteArray();
-    } else {
-      return glyfStream.toByteArray();
-    }
-  }
-
-  public byte[] getPushBytes() {
-    return pushStream.toByteArray();
-  }
-
-  public byte[] getCodeBytes() {
-    return codeStream.toByteArray();
-  }
-
-  public byte[] getLocaBytes() {
-    return new byte[]{ };
-  }
-}
diff --git a/src/com/google/typography/font/compression/GzipUtil.java b/src/com/google/typography/font/compression/GzipUtil.java
deleted file mode 100644
index 75fac1b..0000000
--- a/src/com/google/typography/font/compression/GzipUtil.java
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.google.typography.font.compression;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.zip.Deflater;
-import java.util.zip.DeflaterOutputStream;
-
-/**
- * Simple utility for GZIP compression
- *
- * @author Raph Levien
- */
-public class GzipUtil {
-
-  public static byte[] deflate(byte[] bytes) {
-    try {
-      ByteArrayOutputStream baos = new ByteArrayOutputStream();
-      DeflaterOutputStream dos = new DeflaterOutputStream(baos, new Deflater());
-      dos.write(bytes, 0, bytes.length);
-      dos.close();
-      return baos.toByteArray();
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
-}
-
diff --git a/src/com/google/typography/font/compression/KernEncoder.java b/src/com/google/typography/font/compression/KernEncoder.java
deleted file mode 100644
index 7d94ccb..0000000
--- a/src/com/google/typography/font/compression/KernEncoder.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.google.typography.font.compression;
-
-import com.google.typography.font.sfntly.Font;
-import com.google.typography.font.sfntly.Tag;
-import com.google.typography.font.sfntly.data.ReadableFontData;
-import com.google.typography.font.sfntly.data.WritableFontData;
-import com.google.typography.font.sfntly.table.Table;
-
-/**
- * Encoder for "kern" table. This probably won't go in the spec because an even more
- * effective technique would be to do class kerning in the GDEF tables, but, even so, I wanted
- * to capture the stats.
- *
- * @author Raph Levien
- */
-public class KernEncoder {
-
-  public static WritableFontData encode(Font font) {
-    Table kernTable = font.getTable(Tag.kern);
-    ReadableFontData data = kernTable.readFontData();
-    WritableFontData newData = WritableFontData.createWritableFontData(data.size());
-    data.copyTo(newData);
-    if (data.readUShort(0) == 0 && data.readUShort(4) == 0) {
-      int base = 18;
-      int nPairs = data.readUShort(10);
-      for (int i = 0; i < nPairs; i++) {
-        newData.writeUShort(base + i * 2, data.readUShort(base + i * 6));
-        newData.writeUShort(base + nPairs * 2 + i * 2, data.readUShort(base + i * 6 + 2));
-        newData.writeUShort(base + nPairs * 4 + i * 2, data.readUShort(base + i * 6 + 4));
-      }
-    }
-    return newData;
-  }
-}
diff --git a/src/com/google/typography/font/compression/SimpleRunner.java b/src/com/google/typography/font/compression/SimpleRunner.java
deleted file mode 100644
index 43d554e..0000000
--- a/src/com/google/typography/font/compression/SimpleRunner.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.google.typography.font.compression;
-
-import com.google.common.io.Files;
-import com.google.typography.font.sfntly.Font;
-import com.google.typography.font.sfntly.FontFactory;
-import com.google.typography.font.sfntly.Tag;
-import com.google.typography.font.sfntly.table.truetype.GlyphTable;
-import com.google.typography.font.sfntly.table.truetype.LocaTable;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Simple WOFF 2.0 compression report runner.
- *
- * @author David Kuettel
- */
-public class SimpleRunner {
-
-  private static final FontFactory FONT_FACTORY = FontFactory.getInstance();
-
-  private static final String WOFF = "woff";
-  private static final String WOFF2 = "woff2/lzma";
-
-  private static final String TRUETYPE = "glyf/cbbox,triplet,code,reslice";
-  private static final String CFF = "";
-
-  private static final String REPORT = "report.csv";
-
-  public static void main(String[] args) throws IOException {
-    if (args.length == 0) {
-      usage();
-    }
-    CompressionStats stats = new CompressionStats();
-
-    System.out.printf("Analyzing (%d) fonts\n", args.length);
-    run(stats, args);
-
-    System.out.printf("Creating report: %s\n", REPORT);
-    CsvReport.create(stats, REPORT);
-  }
-
-  private static void run(CompressionStats stats, String[] filenames) throws IOException {
-    for (String filename : filenames) {
-      try {
-        File file = new File(filename);
-        byte[] bytes = Files.toByteArray(file);
-        Font font = FONT_FACTORY.loadFonts(bytes)[0];
-
-        byte[] woff = Experiment.run(font, WOFF);
-        byte[] woff2 = Experiment.run(font, getOptions(font));
-
-        CompressionStats.Stats stat = CompressionStats.Stats.builder()
-            .setFilename(file.getName())
-            .setSize(CompressionStats.Size.ORIGINAL, bytes.length)
-            .setSize(CompressionStats.Size.WOFF, woff.length)
-            .setSize(CompressionStats.Size.WOFF2, woff2.length)
-            .build();
-        stats.add(stat);
-
-        System.out.printf("> %s, %d, %d, %d, %.2f%%\n",
-            stat.getFilename(),
-            stat.getSize(CompressionStats.Size.ORIGINAL),
-            stat.getSize(CompressionStats.Size.WOFF),
-            stat.getSize(CompressionStats.Size.WOFF2),
-            stat.getPercent(CompressionStats.Size.WOFF, CompressionStats.Size.WOFF2));
-
-        String target = filename.replaceAll("[.](ttf|otf)", ".woff2");
-        Files.write(woff2, new File(target));
-
-      } catch (Throwable t) {
-        System.err.printf("WARNING: failed to compress: %s\n", filename);
-        t.printStackTrace();
-      }
-    }
-  }
-
-  private static boolean isTrueType(Font font) {
-    LocaTable loca = font.getTable(Tag.loca);
-    GlyphTable glyf = font.getTable(Tag.glyf);
-    return (loca != null && glyf != null);
-  }
-
-  private static String getOptions(Font font) {
-    return String.format("%s:%s", (isTrueType(font)) ? TRUETYPE : CFF, WOFF2);
-  }
-
-  private static void usage() {
-    System.err.println("Usage: SimpleRunner font...");
-    System.exit(-1);
-  }
-}
diff --git a/src/com/google/typography/font/compression/StatsCollector.java b/src/com/google/typography/font/compression/StatsCollector.java
deleted file mode 100644
index b2fead3..0000000
--- a/src/com/google/typography/font/compression/StatsCollector.java
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.google.typography.font.compression;
-
-import com.google.common.collect.Lists;
-
-import java.io.PrintWriter;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Class for gathering up stats, for summarizing and graphing.
- *
- * @author Raph Levien
- */
-public class StatsCollector {
-
-  private final List<Double> values;
-
-  public StatsCollector() {
-    values = Lists.newArrayList();
-  }
-
-  public void addStat(double value) {
-    values.add(value);
-  }
-
-  public double mean() {
-    double sum = 0;
-    for (Double value : values) {
-      sum += value;
-    }
-    return sum / values.size();
-  }
-
-  public double median() {
-    Collections.sort(values);
-    int length = values.size();
-    if (length % 2 == 1) {
-      return values.get((length - 1) / 2);
-    } else {
-      return 0.5 * (values.get(length / 2 - 1) + values.get(length / 2));
-    }
-  }
-
-  // Need to print <html> before calling this method
-  public void chartHeader(PrintWriter o, int n) {
-    o.println("<head>");
-    o.println("<script type='text/javascript' src='https://www.google.com/jsapi'></script>");
-    o.println("<script type='text/javascript'>");
-    o.println("google.load('visualization', '1', {packages:['corechart']});");
-    o.println("google.setOnLoadCallback(drawChart);");
-    o.println("function drawChart() {");
-    o.println("  var data = new google.visualization.DataTable()");
-    o.println("  data.addColumn('string', 'Font');");
-    if (n == 1) {
-      o.println("  data.addColumn('number', 'Ratio');");
-    } else {
-      for (int i = 0; i < n; i++) {
-        o.printf("  data.addColumn('number', 'Ratio %c');\n", 'A' + i);
-      }
-    }
-    o.printf("  data.addRows(%d);\n", values.size());
-  }
-
-  public void chartData(PrintWriter o, int ix) {
-    Collections.sort(values);
-    int length = values.size();
-    for (int i = 0; i < length; i++) {
-      o.printf("  data.setValue(%d, %d, %f);\n", i, ix, values.get(i));
-    }
-  }
-
-  public void chartEnd(PrintWriter o) {
-    o.println("  var chart = new google.visualization.LineChart(document.getElementById("
-        + "'chart_div'));");
-    o.println("  chart.draw(data, {width:700, height:400, title: 'Compression ratio'});");
-    o.println("}");
-    o.println("</script>");
-    o.println("</head>");
-
-    o.println();
-    o.println("<body>");
-    o.println("<div id='chart_div'></div>");
-    // TODO: split so we can get content into the HTML
-  }
-  public void chartFooter(PrintWriter o) {
-    o.println("</body>");
-    o.println("</html>");
-  }
-}
diff --git a/src/com/google/typography/font/compression/Woff2Writer.java b/src/com/google/typography/font/compression/Woff2Writer.java
deleted file mode 100644
index 905a3ce..0000000
--- a/src/com/google/typography/font/compression/Woff2Writer.java
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright 2012 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.google.typography.font.compression;
-
-import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.Lists;
-import com.google.typography.font.sfntly.Font;
-import com.google.typography.font.sfntly.Tag;
-import com.google.typography.font.sfntly.data.WritableFontData;
-import com.google.typography.font.sfntly.table.Table;
-import com.google.typography.font.sfntly.table.core.FontHeaderTable;
-
-import java.util.List;
-import java.util.TreeSet;
-
-/**
- * @author Raph Levien
- */
-public class Woff2Writer {
-
-  private static final long SIGNATURE = 0x774f4632;
-  private static final int WOFF2_HEADER_SIZE = 44;
-  private static final int TABLE_ENTRY_SIZE = 5 * 4;
-  private static final int FLAG_CONTINUE_STREAM = 1 << 4;
-  private static final int FLAG_APPLY_TRANSFORM = 1 << 5;
-
-  private final CompressionType compressionType;
-  private final boolean longForm;
-
-  public Woff2Writer(String args) {
-    CompressionType compressionType = CompressionType.NONE;
-    boolean longForm = false;
-    for (String arg : args.split(",")) {
-      if ("lzma".equals(arg)) {
-        compressionType = CompressionType.LZMA;
-      } else if ("gzip".equals(arg)) {
-        compressionType = CompressionType.GZIP;
-      } else if ("short".equals(arg)) {
-        longForm = false;
-      } else if ("long".equals(arg)) {
-        longForm = true;
-      }
-    }
-    this.compressionType = compressionType;
-    this.longForm = longForm;
-  }
-
-  private static ImmutableBiMap<Integer, Integer> TRANSFORM_MAP = ImmutableBiMap.of(
-      Tag.glyf, Tag.intValue(new byte[] {'g', 'l', 'z', '1'}),
-      Tag.loca, Tag.intValue(new byte[] {'l', 'o', 'c', 'z'})
-  );
-
-  public static ImmutableBiMap<Integer, Integer> getTransformMap() {
-    return TRANSFORM_MAP;
-  }
-
-  private static ImmutableBiMap<Integer, Integer> KNOWN_TABLES =
-      new ImmutableBiMap.Builder<Integer, Integer>()
-      .put(Tag.intValue(new byte[] {'c', 'm', 'a', 'p'}), 0)
-      .put(Tag.intValue(new byte[] {'h', 'e', 'a', 'd'}), 1)
-      .put(Tag.intValue(new byte[] {'h', 'h', 'e', 'a'}), 2)
-      .put(Tag.intValue(new byte[] {'h', 'm', 't', 'x'}), 3)
-      .put(Tag.intValue(new byte[] {'m', 'a', 'x', 'p'}), 4)
-      .put(Tag.intValue(new byte[] {'n', 'a', 'm', 'e'}), 5)
-      .put(Tag.intValue(new byte[] {'O', 'S', '/', '2'}), 6)
-      .put(Tag.intValue(new byte[] {'p', 'o', 's', 't'}), 7)
-      .put(Tag.intValue(new byte[] {'c', 'v', 't', ' '}), 8)
-      .put(Tag.intValue(new byte[] {'f', 'p', 'g', 'm'}), 9)
-      .put(Tag.intValue(new byte[] {'g', 'l', 'y', 'f'}), 10)
-      .put(Tag.intValue(new byte[] {'l', 'o', 'c', 'a'}), 11)
-      .put(Tag.intValue(new byte[] {'p', 'r', 'e', 'p'}), 12)
-      .put(Tag.intValue(new byte[] {'C', 'F', 'F', ' '}), 13)
-      .put(Tag.intValue(new byte[] {'V', 'O', 'R', 'G'}), 14)
-      .put(Tag.intValue(new byte[] {'E', 'B', 'D', 'T'}), 15)
-      .put(Tag.intValue(new byte[] {'E', 'B', 'L', 'C'}), 16)
-      .put(Tag.intValue(new byte[] {'g', 'a', 's', 'p'}), 17)
-      .put(Tag.intValue(new byte[] {'h', 'd', 'm', 'x'}), 18)
-      .put(Tag.intValue(new byte[] {'k', 'e', 'r', 'n'}), 19)
-      .put(Tag.intValue(new byte[] {'L', 'T', 'S', 'H'}), 20)
-      .put(Tag.intValue(new byte[] {'P', 'C', 'L', 'T'}), 21)
-      .put(Tag.intValue(new byte[] {'V', 'D', 'M', 'X'}), 22)
-      .put(Tag.intValue(new byte[] {'v', 'h', 'e', 'a'}), 23)
-      .put(Tag.intValue(new byte[] {'v', 'm', 't', 'x'}), 24)
-      .put(Tag.intValue(new byte[] {'B', 'A', 'S', 'E'}), 25)
-      .put(Tag.intValue(new byte[] {'G', 'D', 'E', 'F'}), 26)
-      .put(Tag.intValue(new byte[] {'G', 'P', 'O', 'S'}), 27)
-      .put(Tag.intValue(new byte[] {'G', 'S', 'U', 'B'}), 28)
-      .build();
-
-  public WritableFontData convert(Font font) {
-    List<TableDirectoryEntry> entries = createTableDirectoryEntries(font);
-    int size = computeCompressedFontSize(entries);
-    WritableFontData writableFontData = WritableFontData.createWritableFontData(size);
-    int index = 0;
-    FontHeaderTable head = font.getTable(Tag.head);
-    index += writeWoff2Header(writableFontData, entries, font.sfntVersion(), size,
-        head.fontRevision());
-//    System.out.printf("Wrote header, index = %d\n", index);
-    index += writeDirectory(writableFontData, index, entries);
-//    System.out.printf("Wrote directory, index = %d\n", index);
-    index += writeTables(writableFontData, index, entries);
-//    System.out.printf("Wrote tables, index = %d\n", index);
-    return writableFontData;
-  }
-
-  private List<TableDirectoryEntry> createTableDirectoryEntries(Font font) {
-    List<TableDirectoryEntry> entries = Lists.newArrayList();
-    TreeSet<Integer> tags = new TreeSet<Integer>(font.tableMap().keySet());
-
-    for (int tag : tags) {
-      Table table = font.getTable(tag);
-      byte[] uncompressedBytes = bytesFromTable(table);
-      byte[] transformedBytes = null;
-      if (TRANSFORM_MAP.containsValue(tag)) {
-        // Don't store the intermediate transformed tables under the nonstandard tags.
-        continue;
-      }
-      if (TRANSFORM_MAP.containsKey(tag)) {
-        int transformedTag = TRANSFORM_MAP.get(tag);
-        Table transformedTable = font.getTable(transformedTag);
-        if (transformedTable != null) {
-          transformedBytes = bytesFromTable(transformedTable);
-        }
-      }
-      if (transformedBytes == null) {
-        entries.add(new TableDirectoryEntry(tag, uncompressedBytes, compressionType));
-      } else {
-        entries.add(new TableDirectoryEntry(tag, uncompressedBytes, transformedBytes,
-            FLAG_APPLY_TRANSFORM, compressionType));
-      }
-    }
-    return entries;
-  }
-
-  private byte[] bytesFromTable(Table table) {
-    int length = table.dataLength();
-    byte[] bytes = new byte[length];
-    table.readFontData().readBytes(0, bytes, 0, length);
-    return bytes;
-  }
-
-  private int writeWoff2Header(WritableFontData writableFontData,
-      List<TableDirectoryEntry> entries,
-      int flavor,
-      int length,
-      int version) {
-    int index = 0;
-    index += writableFontData.writeULong(index, SIGNATURE);
-    index += writableFontData.writeULong(index, flavor);
-    index += writableFontData.writeULong(index, length);
-    index += writableFontData.writeUShort(index, entries.size());  // numTables
-    index += writableFontData.writeUShort(index, 0);  // reserved
-    int uncompressedFontSize = computeUncompressedSize(entries);
-    index += writableFontData.writeULong(index, uncompressedFontSize);
-    index += writableFontData.writeFixed(index, version);
-    index += writableFontData.writeULong(index, 0);  // metaOffset
-    index += writableFontData.writeULong(index, 0);  // metaLength
-    index += writableFontData.writeULong(index, 0);  // metaOrigLength
-    index += writableFontData.writeULong(index, 0);  // privOffset
-    index += writableFontData.writeULong(index, 0);  // privLength
-    return index;
-  }
-
-  private int writeDirectory(WritableFontData writableFontData, int offset,
-      List<TableDirectoryEntry> entries) {
-    int directorySize = computeDirectoryLength(entries);
-    for (TableDirectoryEntry entry : entries) {
-      offset += entry.writeEntry(writableFontData, offset);
-    }
-    return directorySize;
-  }
-
-  private int writeTables(WritableFontData writableFontData, int offset,
-      List<TableDirectoryEntry> entries) {
-    int start = offset;
-    for (TableDirectoryEntry entry : entries) {
-      offset += entry.writeData(writableFontData, offset);
-      offset = align4(offset);
-    }
-    return offset - start;
-  }
-
-  private int computeDirectoryLength(List<TableDirectoryEntry> entries) {
-    if (longForm) {
-      return TABLE_ENTRY_SIZE * entries.size();
-    } else {
-      int size = 0;
-      for (TableDirectoryEntry entry : entries) {
-        size += entry.writeEntry(null, size);
-      }
-      return size;
-    }
-  }
-
-  private int align4(int value) {
-    return (value + 3) & -4;
-  }
-
-  private int computeUncompressedSize(List<TableDirectoryEntry> entries) {
-    int size = 20 + 16 * entries.size();  // sfnt header length
-    for (TableDirectoryEntry entry : entries) {
-      size += entry.getOrigLength();
-      size = align4(size);
-    }
-    return size;
-  }
-
-  private int computeCompressedFontSize(List<TableDirectoryEntry> entries) {
-    int fontSize = WOFF2_HEADER_SIZE;
-    fontSize += computeDirectoryLength(entries);
-    for (TableDirectoryEntry entry : entries) {
-      fontSize += entry.getCompLength();
-      fontSize = align4(fontSize);
-    }
-    return fontSize;
-  }
-
-  private enum CompressionType {
-    NONE, GZIP, LZMA
-  }
-
-  private static long flagsForCompression(CompressionType compressionType) {
-    switch (compressionType) {
-      case NONE:
-        return 0;
-      case GZIP:
-        return 1;
-      case LZMA:
-        return 2;
-    }
-    return 0;
-  }
-
-  private static byte[] compress(byte[] input, CompressionType compressionType) {
-    switch (compressionType) {
-      case NONE:
-        return input;
-      case GZIP:
-        return GzipUtil.deflate(input);
-      case LZMA:
-        return CompressLzma.compress(input);
-    }
-    return null;
-  }
-
-  // Note: if writableFontData is null, just return the size
-  private static int writeBase128(WritableFontData writableFontData, long value, int offset) {
-    int size = 1;
-    long tmpValue = value;
-    while (tmpValue >= 128) {
-      size += 1;
-      tmpValue = tmpValue >> 7;
-    }
-    for (int i = 0; i < size; i++) {
-      int b = (int)(value >> (7 * (size - i - 1))) & 0x7f;
-      if (i < size - 1) {
-        b |= 0x80;
-      }
-      if (writableFontData != null) {
-        writableFontData.writeByte(offset, (byte)b);
-      }
-      offset += 1;
-    }
-    return size;
-  }
-
-  private class TableDirectoryEntry {
-    private final long tag;
-    private final long flags;
-    private final long origLength;
-    private final long transformLength;
-    private final byte[] bytes;
-
-    // This is the constructor for tables that don't have transforms
-    public TableDirectoryEntry(long tag, byte[] uncompressedBytes,
-        CompressionType compressionType) {
-      this(tag, uncompressedBytes, uncompressedBytes, 0, compressionType);
-    }
-
-    public TableDirectoryEntry(long tag, byte[] uncompressedBytes, byte[] transformedBytes,
-        long transformFlags, CompressionType compressionType) {
-      byte[] compressedBytes = compress(transformedBytes, compressionType);
-      if (compressedBytes.length >= transformedBytes.length) {
-        compressedBytes = transformedBytes;
-        compressionType = CompressionType.NONE;
-      }
-      this.tag = tag;
-      this.flags = transformFlags | flagsForCompression(compressionType);
-      this.origLength = uncompressedBytes.length;
-      this.transformLength = transformedBytes.length;
-      this.bytes = compressedBytes;
-    }
-
-    public long getOrigLength() {
-      return origLength;
-    }
-
-    public long getCompLength() {
-      return bytes.length;
-    }
-
-    // Note: if writableFontData is null, just return the size
-    public int writeEntry(WritableFontData writableFontData, int offset) {
-      if (longForm) {
-        if (writableFontData != null) {
-          offset += writableFontData.writeULong(offset, tag);
-          offset += writableFontData.writeULong(offset, flags);
-          offset += writableFontData.writeULong(offset, getCompLength());
-          offset += writableFontData.writeULong(offset, transformLength);
-          offset += writableFontData.writeULong(offset, getOrigLength());
-        }
-        return TABLE_ENTRY_SIZE;
-      } else {
-        int start = offset;
-        int flag_byte = 0x1f;
-        if (KNOWN_TABLES.containsKey((int)tag)) {
-          flag_byte = KNOWN_TABLES.get((int)tag);
-        }
-        if ((flags & FLAG_APPLY_TRANSFORM) != 0) {
-          flag_byte |= 0x20;
-        }
-        if ((flags & FLAG_CONTINUE_STREAM) != 0) {
-          flag_byte |= 0xc0;
-        } else {
-          flag_byte |= (flags & 3) << 6;
-        }
-        if (writableFontData != null) {
-//          System.out.printf("%d: tag = %08x, flag = %02x\n", offset, tag, flag_byte);
-          writableFontData.writeByte(offset, (byte)flag_byte);
-        }
-        offset += 1;
-        if ((flag_byte & 0x1f) == 0x1f) {
-          if (writableFontData != null) {
-            writableFontData.writeULong(offset, tag);
-          }
-          offset += 4;
-        }
-        offset += writeBase128(writableFontData, getOrigLength(), offset);
-        if ((flag_byte & 0x20) != 0) {
-          offset += writeBase128(writableFontData, transformLength, offset);
-        }
-        if ((flag_byte & 0xc0) == 0x40 || (flag_byte & 0xc0) == 0x80) {
-          offset += writeBase128(writableFontData, getCompLength(), offset);
-        }
-        return offset - start;
-      }
-    }
-
-    public int writeData(WritableFontData writableFontData, int offset) {
-      writableFontData.writeBytes(offset, bytes);
-      return bytes.length;
-    }
-  }
-}