diff --git a/Makefile b/Makefile index 622a2af..4b3bd7b 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ DECOBJ = $(BROTLIOBJ)/dec/*.o COMMONOBJ = $(BROTLIOBJ)/common/*.o OBJS = $(patsubst %, $(SRCDIR)/%, $(OUROBJ)) -EXECUTABLES=woff2_compress woff2_decompress +EXECUTABLES=woff2_compress woff2_decompress woff2_info EXE_OBJS=$(patsubst %, $(SRCDIR)/%.o, $(EXECUTABLES)) ARCHIVES=convert_woff2ttf_fuzzer convert_woff2ttf_fuzzer_new_entry ARCHIVE_OBJS=$(patsubst %, $(SRCDIR)/%.o, $(ARCHIVES)) diff --git a/src/woff2_info.cc b/src/woff2_info.cc new file mode 100644 index 0000000..5dff871 --- /dev/null +++ b/src/woff2_info.cc @@ -0,0 +1,152 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// A commandline tool for dumping info about a woff2 file. + +#include + +#include "file.h" +#include "./woff2_common.h" +#include "./buffer.h" +#include "./font.h" +#include "./table_tags.h" +#include "./variable_length.h" + +std::string PrintTag(int tag) { + if (tag & 0x80808080) { + return std::string("_xfm"); // print _xfm for xform tables (else garbage) + } + char printable[] = { + static_cast((tag >> 24) & 0xFF), + static_cast((tag >> 16) & 0xFF), + static_cast((tag >> 8) & 0xFF), + static_cast(tag & 0xFF) + }; + return std::string(printable, 4); +} + +int main(int argc, char **argv) { + using std::string; + + if (argc != 2) { + fprintf(stderr, "One argument, the input filename, must be provided.\n"); + return 1; + } + + string filename(argv[1]); + string outfilename = filename.substr(0, filename.find_last_of(".")) + ".woff2"; + fprintf(stdout, "Processing %s => %s\n", + filename.c_str(), outfilename.c_str()); + string input = woff2::GetFileContent(filename); + + woff2::Buffer file(reinterpret_cast(input.data()), + input.size()); + + printf("WOFF2Header\n"); + uint32_t signature, flavor, length, totalSfntSize, totalCompressedSize; + uint32_t metaOffset, metaLength, metaOrigLength, privOffset, privLength; + uint16_t num_tables, reserved, major, minor; + if (!file.ReadU32(&signature)) return 1; + if (!file.ReadU32(&flavor)) return 1; + if (!file.ReadU32(&length)) return 1; + if (!file.ReadU16(&num_tables)) return 1; + if (!file.ReadU16(&reserved)) return 1; + if (!file.ReadU32(&totalSfntSize)) return 1; + if (!file.ReadU32(&totalCompressedSize)) return 1; + if (!file.ReadU16(&major)) return 1; + if (!file.ReadU16(&minor)) return 1; + if (!file.ReadU32(&metaOffset)) return 1; + if (!file.ReadU32(&metaLength)) return 1; + if (!file.ReadU32(&metaOrigLength)) return 1; + if (!file.ReadU32(&privOffset)) return 1; + if (!file.ReadU32(&privLength)) return 1; + + if (signature != 0x774F4632) { + printf("Invalid signature: %08x\n", signature); + return 1; + } + printf("signature 0x%08x\n", signature); + printf("flavor 0x%08x\n", flavor); + printf("length %d\n", length); + printf("numTables %d\n", num_tables); + printf("reserved %d\n", reserved); + printf("totalSfntSize %d\n", totalSfntSize); + printf("totalCompressedSize %d\n", totalCompressedSize); + printf("majorVersion %d\n", major); + printf("minorVersion %d\n", minor); + printf("metaOffset %d\n", metaOffset); + printf("metaLength %d\n", metaLength); + printf("metaOrigLength %d\n", metaOrigLength); + printf("privOffset %d\n", privOffset); + printf("privLength %d\n", privLength); + + std::vector table_tags; + printf("TableDirectory starts at +%zu\n", file.offset()); + printf("Entry offset flags tag origLength txLength\n"); + for (auto i = 0; i < num_tables; i++) { + size_t offset = file.offset(); + uint8_t flags; + uint32_t tag, origLength, transformLength; + if (!file.ReadU8(&flags)) return 1; + if ((flags & 0x3f) == 0x3f) { + if (!file.ReadU32(&tag)) return 1; + } else { + tag = woff2::kKnownTags[flags & 0x3f]; + } + table_tags.push_back(tag); + if (!ReadBase128(&file, &origLength)) return 1; + + printf("%5d %6zu 0x%02x %s %10d", i, offset, flags, + PrintTag(tag).c_str(), origLength); + + uint8_t xform_version = (flags >> 6) & 0x3; + if (tag == woff2::kGlyfTableTag || tag == woff2::kLocaTableTag) { + if (xform_version == 0) { + if (!ReadBase128(&file, &transformLength)) return 1; + printf(" %8d", transformLength); + } + } else if (xform_version > 0) { + if (!ReadBase128(&file, &transformLength)) return 1; + printf(" %8d", transformLength); + } + printf("\n"); + } + + // Collection header + if (flavor == woff2::kTtcFontFlavor) { + uint32_t version, numFonts; + if (!file.ReadU32(&version)) return 1; + if (!woff2::Read255UShort(&file, &numFonts)) return 1; + printf("CollectionHeader 0x%08x %d fonts\n", version, numFonts); + + for (auto i = 0; i < numFonts; i++) { + uint32_t numTables, flavor; + if (!woff2::Read255UShort(&file, &numTables)) return 1; + if (!file.ReadU32(&flavor)) return 1; + printf("CollectionFontEntry %d flavor 0x%08x %d tables\n", i, flavor, + numTables); + for (auto j = 0; j < numTables; j++) { + uint32_t table_idx; + if (!woff2::Read255UShort(&file, &table_idx)) return 1; + if (table_idx >= table_tags.size()) return 1; + printf(" %d %s (idx %d)\n", j, + PrintTag(table_tags[table_idx]).c_str(), table_idx); + } + } + } + + printf("TableDirectory ends at +%zu\n", file.offset()); + + return 0; +}