xref: /aosp_15_r20/external/harfbuzz_ng/generate_notice.py (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*2d1272b8SAndroid Build Coastguard Worker
3*2d1272b8SAndroid Build Coastguard Workerfrom enum import Enum
4*2d1272b8SAndroid Build Coastguard Workerfrom pathlib import Path
5*2d1272b8SAndroid Build Coastguard Workerfrom typing import Sequence
6*2d1272b8SAndroid Build Coastguard Workerfrom typing import Tuple
7*2d1272b8SAndroid Build Coastguard Workerfrom fontTools import ttLib
8*2d1272b8SAndroid Build Coastguard Workerimport tempfile
9*2d1272b8SAndroid Build Coastguard Workerimport subprocess
10*2d1272b8SAndroid Build Coastguard Workerimport json
11*2d1272b8SAndroid Build Coastguard Workerimport argparse
12*2d1272b8SAndroid Build Coastguard Workerimport contextlib
13*2d1272b8SAndroid Build Coastguard Workerimport os
14*2d1272b8SAndroid Build Coastguard Workerimport re
15*2d1272b8SAndroid Build Coastguard Workerimport sys
16*2d1272b8SAndroid Build Coastguard Worker
17*2d1272b8SAndroid Build Coastguard Worker# list of specific files to be ignored.
18*2d1272b8SAndroid Build Coastguard WorkerIGNORE_FILE_NAME = [
19*2d1272b8SAndroid Build Coastguard Worker  # Exclude myself
20*2d1272b8SAndroid Build Coastguard Worker  "generate_notice.py",
21*2d1272b8SAndroid Build Coastguard Worker
22*2d1272b8SAndroid Build Coastguard Worker  # License files
23*2d1272b8SAndroid Build Coastguard Worker  "LICENSE",
24*2d1272b8SAndroid Build Coastguard Worker  "LICENSE_APACHE2.TXT",
25*2d1272b8SAndroid Build Coastguard Worker  "LICENSE_FSFAP.TXT",
26*2d1272b8SAndroid Build Coastguard Worker  "LICENSE_GPLv2.TXT",
27*2d1272b8SAndroid Build Coastguard Worker  "LICENSE_GPLv2_WITH_AUTOCONF_EXCEPTION.TXT",
28*2d1272b8SAndroid Build Coastguard Worker  "LICENSE_GPLv3_WITH_AUTOCONF_EXCEPTION.TXT",
29*2d1272b8SAndroid Build Coastguard Worker  "LICENSE_HPND_SELL_VARIANT.TXT",
30*2d1272b8SAndroid Build Coastguard Worker  "LICENSE_ISC.TXT",
31*2d1272b8SAndroid Build Coastguard Worker  "LICENSE_MIT_MODERN_VARIANT.TXT",
32*2d1272b8SAndroid Build Coastguard Worker  "LICENSE_OFL.TXT",
33*2d1272b8SAndroid Build Coastguard Worker  "METADATA",
34*2d1272b8SAndroid Build Coastguard Worker  "MODULE_LICENSE_MIT",
35*2d1272b8SAndroid Build Coastguard Worker  "NOTICE",
36*2d1272b8SAndroid Build Coastguard Worker
37*2d1272b8SAndroid Build Coastguard Worker  # dictionary which has Copyright word
38*2d1272b8SAndroid Build Coastguard Worker  "perf/texts/en-words.txt",
39*2d1272b8SAndroid Build Coastguard Worker
40*2d1272b8SAndroid Build Coastguard Worker  # broken unreadable font file for fuzzing target
41*2d1272b8SAndroid Build Coastguard Worker  "test/fuzzing/fonts/sbix-extents.ttf",
42*2d1272b8SAndroid Build Coastguard Worker
43*2d1272b8SAndroid Build Coastguard Worker  # ???
44*2d1272b8SAndroid Build Coastguard Worker  "xkcd.png",
45*2d1272b8SAndroid Build Coastguard Worker]
46*2d1272b8SAndroid Build Coastguard Worker
47*2d1272b8SAndroid Build Coastguard WorkerIGNORE_DIR_IF_NO_COPYRIGHT = [
48*2d1272b8SAndroid Build Coastguard Worker    "test",
49*2d1272b8SAndroid Build Coastguard Worker    "perf",
50*2d1272b8SAndroid Build Coastguard Worker]
51*2d1272b8SAndroid Build Coastguard Worker
52*2d1272b8SAndroid Build Coastguard WorkerNO_COPYRIGHT_FILES = [
53*2d1272b8SAndroid Build Coastguard Worker  ".ci/build-win32.sh",
54*2d1272b8SAndroid Build Coastguard Worker  ".ci/build-win64.sh",
55*2d1272b8SAndroid Build Coastguard Worker  ".ci/deploy-docs.sh",
56*2d1272b8SAndroid Build Coastguard Worker  ".ci/publish_release_artifact.sh",
57*2d1272b8SAndroid Build Coastguard Worker  ".ci/requirements-fonttools.in",
58*2d1272b8SAndroid Build Coastguard Worker  ".ci/requirements-fonttools.txt",
59*2d1272b8SAndroid Build Coastguard Worker  ".ci/requirements.in",
60*2d1272b8SAndroid Build Coastguard Worker  ".ci/requirements.txt",
61*2d1272b8SAndroid Build Coastguard Worker  ".ci/win32-cross-file.txt",
62*2d1272b8SAndroid Build Coastguard Worker  ".ci/win64-cross-file.txt",
63*2d1272b8SAndroid Build Coastguard Worker  ".circleci/config.yml",
64*2d1272b8SAndroid Build Coastguard Worker  ".clang-format",
65*2d1272b8SAndroid Build Coastguard Worker  ".codecov.yml",
66*2d1272b8SAndroid Build Coastguard Worker  ".editorconfig",
67*2d1272b8SAndroid Build Coastguard Worker  ".github/dependabot.yml",
68*2d1272b8SAndroid Build Coastguard Worker  ".github/workflows/arm-ci.yml",
69*2d1272b8SAndroid Build Coastguard Worker  ".github/workflows/cifuzz.yml",
70*2d1272b8SAndroid Build Coastguard Worker  ".github/workflows/configs-build.yml",
71*2d1272b8SAndroid Build Coastguard Worker  ".github/workflows/coverity-scan.yml",
72*2d1272b8SAndroid Build Coastguard Worker  ".github/workflows/linux-ci.yml",
73*2d1272b8SAndroid Build Coastguard Worker  ".github/workflows/macos-ci.yml",
74*2d1272b8SAndroid Build Coastguard Worker  ".github/workflows/msvc-ci.yml",
75*2d1272b8SAndroid Build Coastguard Worker  ".github/workflows/msys2-ci.yml",
76*2d1272b8SAndroid Build Coastguard Worker  ".github/workflows/scorecard.yml",
77*2d1272b8SAndroid Build Coastguard Worker  "AUTHORS",
78*2d1272b8SAndroid Build Coastguard Worker  "BUILD.md",
79*2d1272b8SAndroid Build Coastguard Worker  "CMakeLists.txt",
80*2d1272b8SAndroid Build Coastguard Worker  "CONFIG.md",
81*2d1272b8SAndroid Build Coastguard Worker  "NEWS",
82*2d1272b8SAndroid Build Coastguard Worker  "OWNERS",
83*2d1272b8SAndroid Build Coastguard Worker  "README.android",
84*2d1272b8SAndroid Build Coastguard Worker  "README.md",
85*2d1272b8SAndroid Build Coastguard Worker  "README.python.md",
86*2d1272b8SAndroid Build Coastguard Worker  "RELEASING.md",
87*2d1272b8SAndroid Build Coastguard Worker  "SECURITY.md",
88*2d1272b8SAndroid Build Coastguard Worker  "TESTING.md",
89*2d1272b8SAndroid Build Coastguard Worker  "TEST_MAPPING",
90*2d1272b8SAndroid Build Coastguard Worker  "THANKS",
91*2d1272b8SAndroid Build Coastguard Worker  "docs/HarfBuzz.png",
92*2d1272b8SAndroid Build Coastguard Worker  "docs/HarfBuzz.svg",
93*2d1272b8SAndroid Build Coastguard Worker  "docs/features.dot",
94*2d1272b8SAndroid Build Coastguard Worker  "docs/harfbuzz-docs.xml",
95*2d1272b8SAndroid Build Coastguard Worker  "docs/harfbuzz-overrides.txt",
96*2d1272b8SAndroid Build Coastguard Worker  "docs/harfbuzz-sections.txt",
97*2d1272b8SAndroid Build Coastguard Worker  "docs/meson.build",
98*2d1272b8SAndroid Build Coastguard Worker  "docs/repacker.md",
99*2d1272b8SAndroid Build Coastguard Worker  "docs/serializer.md",
100*2d1272b8SAndroid Build Coastguard Worker  "docs/subset-preprocessing.md",
101*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-buffers-language-script-and-direction.xml",
102*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-clusters.xml",
103*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-fonts-and-faces.xml",
104*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-getting-started.xml",
105*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-glyph-information.xml",
106*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-install-harfbuzz.xml",
107*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-integration.xml",
108*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-object-model.xml",
109*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-opentype-features.xml",
110*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-shaping-concepts.xml",
111*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-utilities.xml",
112*2d1272b8SAndroid Build Coastguard Worker  "docs/usermanual-what-is-harfbuzz.xml",
113*2d1272b8SAndroid Build Coastguard Worker  "docs/version.xml.in",
114*2d1272b8SAndroid Build Coastguard Worker  "docs/wasm-shaper.md",
115*2d1272b8SAndroid Build Coastguard Worker  "harfbuzz.doap",
116*2d1272b8SAndroid Build Coastguard Worker  "meson.build",
117*2d1272b8SAndroid Build Coastguard Worker  "meson_options.txt",
118*2d1272b8SAndroid Build Coastguard Worker  "replace-enum-strings.cmake",
119*2d1272b8SAndroid Build Coastguard Worker  "src/ArabicPUASimplified.txt",
120*2d1272b8SAndroid Build Coastguard Worker  "src/ArabicPUATraditional.txt",
121*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/Anchor.hh",
122*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/AnchorFormat1.hh",
123*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/AnchorFormat2.hh",
124*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/AnchorFormat3.hh",
125*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/AnchorMatrix.hh",
126*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/ChainContextPos.hh",
127*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/Common.hh",
128*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/ContextPos.hh",
129*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/CursivePos.hh",
130*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/CursivePosFormat1.hh",
131*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/ExtensionPos.hh",
132*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/GPOS.hh",
133*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/LigatureArray.hh",
134*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/MarkArray.hh",
135*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/MarkBasePos.hh",
136*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/MarkBasePosFormat1.hh",
137*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/MarkLigPos.hh",
138*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/MarkLigPosFormat1.hh",
139*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/MarkMarkPos.hh",
140*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/MarkMarkPosFormat1.hh",
141*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/MarkRecord.hh",
142*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/PairPos.hh",
143*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/PairPosFormat1.hh",
144*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/PairPosFormat2.hh",
145*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/PairSet.hh",
146*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/PairValueRecord.hh",
147*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/PosLookup.hh",
148*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/PosLookupSubTable.hh",
149*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/SinglePos.hh",
150*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/SinglePosFormat1.hh",
151*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/SinglePosFormat2.hh",
152*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GPOS/ValueFormat.hh",
153*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/AlternateSet.hh",
154*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/AlternateSubst.hh",
155*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/AlternateSubstFormat1.hh",
156*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/ChainContextSubst.hh",
157*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/Common.hh",
158*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/ContextSubst.hh",
159*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/ExtensionSubst.hh",
160*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/GSUB.hh",
161*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/Ligature.hh",
162*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/LigatureSet.hh",
163*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/LigatureSubst.hh",
164*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/LigatureSubstFormat1.hh",
165*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/MultipleSubst.hh",
166*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/MultipleSubstFormat1.hh",
167*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/ReverseChainSingleSubst.hh",
168*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh",
169*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/Sequence.hh",
170*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/SingleSubst.hh",
171*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/SingleSubstFormat1.hh",
172*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/SingleSubstFormat2.hh",
173*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/SubstLookup.hh",
174*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Layout/GSUB/SubstLookupSubTable.hh",
175*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Var/VARC/VARC.cc",
176*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Var/VARC/VARC.hh",
177*2d1272b8SAndroid Build Coastguard Worker  "src/OT/Var/VARC/coord-setter.hh",
178*2d1272b8SAndroid Build Coastguard Worker  "src/OT/glyf/CompositeGlyph.hh",
179*2d1272b8SAndroid Build Coastguard Worker  "src/OT/glyf/Glyph.hh",
180*2d1272b8SAndroid Build Coastguard Worker  "src/OT/glyf/GlyphHeader.hh",
181*2d1272b8SAndroid Build Coastguard Worker  "src/OT/glyf/SimpleGlyph.hh",
182*2d1272b8SAndroid Build Coastguard Worker  "src/OT/glyf/SubsetGlyph.hh",
183*2d1272b8SAndroid Build Coastguard Worker  "src/OT/glyf/composite-iter.hh",
184*2d1272b8SAndroid Build Coastguard Worker  "src/OT/glyf/glyf-helpers.hh",
185*2d1272b8SAndroid Build Coastguard Worker  "src/OT/glyf/glyf.hh",
186*2d1272b8SAndroid Build Coastguard Worker  "src/OT/glyf/loca.hh",
187*2d1272b8SAndroid Build Coastguard Worker  "src/OT/glyf/path-builder.hh",
188*2d1272b8SAndroid Build Coastguard Worker  "src/addTable.py",
189*2d1272b8SAndroid Build Coastguard Worker  "src/check-c-linkage-decls.py",
190*2d1272b8SAndroid Build Coastguard Worker  "src/check-externs.py",
191*2d1272b8SAndroid Build Coastguard Worker  "src/check-header-guards.py",
192*2d1272b8SAndroid Build Coastguard Worker  "src/check-includes.py",
193*2d1272b8SAndroid Build Coastguard Worker  "src/check-libstdc++.py",
194*2d1272b8SAndroid Build Coastguard Worker  "src/check-static-inits.py",
195*2d1272b8SAndroid Build Coastguard Worker  "src/check-symbols.py",
196*2d1272b8SAndroid Build Coastguard Worker  "src/fix_get_types.py",
197*2d1272b8SAndroid Build Coastguard Worker  "src/gen-arabic-joining-list.py",
198*2d1272b8SAndroid Build Coastguard Worker  "src/gen-arabic-pua.py",
199*2d1272b8SAndroid Build Coastguard Worker  "src/gen-arabic-table.py",
200*2d1272b8SAndroid Build Coastguard Worker  "src/gen-def.py",
201*2d1272b8SAndroid Build Coastguard Worker  "src/gen-emoji-table.py",
202*2d1272b8SAndroid Build Coastguard Worker  "src/gen-harfbuzzcc.py",
203*2d1272b8SAndroid Build Coastguard Worker  "src/gen-hb-version.py",
204*2d1272b8SAndroid Build Coastguard Worker  "src/gen-indic-table.py",
205*2d1272b8SAndroid Build Coastguard Worker  "src/gen-os2-unicode-ranges.py",
206*2d1272b8SAndroid Build Coastguard Worker  "src/gen-ragel-artifacts.py",
207*2d1272b8SAndroid Build Coastguard Worker  "src/gen-tag-table.py",
208*2d1272b8SAndroid Build Coastguard Worker  "src/gen-ucd-table.py",
209*2d1272b8SAndroid Build Coastguard Worker  "src/gen-use-table.py",
210*2d1272b8SAndroid Build Coastguard Worker  "src/gen-vowel-constraints.py",
211*2d1272b8SAndroid Build Coastguard Worker  "src/harfbuzz-cairo.pc.in",
212*2d1272b8SAndroid Build Coastguard Worker  "src/harfbuzz-config.cmake.in",
213*2d1272b8SAndroid Build Coastguard Worker  "src/harfbuzz-gobject.pc.in",
214*2d1272b8SAndroid Build Coastguard Worker  "src/harfbuzz-icu.pc.in",
215*2d1272b8SAndroid Build Coastguard Worker  "src/harfbuzz-subset.cc",
216*2d1272b8SAndroid Build Coastguard Worker  "src/harfbuzz-subset.pc.in",
217*2d1272b8SAndroid Build Coastguard Worker  "src/harfbuzz.cc",
218*2d1272b8SAndroid Build Coastguard Worker  "src/harfbuzz.pc.in",
219*2d1272b8SAndroid Build Coastguard Worker  "src/hb-ot-shaper-arabic-joining-list.hh",
220*2d1272b8SAndroid Build Coastguard Worker  "src/hb-ot-shaper-arabic-pua.hh",
221*2d1272b8SAndroid Build Coastguard Worker  "src/hb-ot-shaper-arabic-table.hh",
222*2d1272b8SAndroid Build Coastguard Worker  "src/hb-ot-shaper-indic-table.cc",
223*2d1272b8SAndroid Build Coastguard Worker  "src/hb-ot-shaper-use-table.hh",
224*2d1272b8SAndroid Build Coastguard Worker  "src/hb-ot-shaper-vowel-constraints.cc",
225*2d1272b8SAndroid Build Coastguard Worker  "src/hb-ot-tag-table.hh",
226*2d1272b8SAndroid Build Coastguard Worker  "src/hb-ucd-table.hh",
227*2d1272b8SAndroid Build Coastguard Worker  "src/hb-unicode-emoji-table.hh",
228*2d1272b8SAndroid Build Coastguard Worker  "src/justify.py",
229*2d1272b8SAndroid Build Coastguard Worker  "src/meson.build",
230*2d1272b8SAndroid Build Coastguard Worker  "src/ms-use/IndicPositionalCategory-Additional.txt",
231*2d1272b8SAndroid Build Coastguard Worker  "src/ms-use/IndicShapingInvalidCluster.txt",
232*2d1272b8SAndroid Build Coastguard Worker  "src/ms-use/IndicSyllabicCategory-Additional.txt",
233*2d1272b8SAndroid Build Coastguard Worker  "src/relative_to.py",
234*2d1272b8SAndroid Build Coastguard Worker  "src/sample.py",
235*2d1272b8SAndroid Build Coastguard Worker  "src/test-use-table.cc",
236*2d1272b8SAndroid Build Coastguard Worker  "src/update-unicode-tables.make",
237*2d1272b8SAndroid Build Coastguard Worker  "src/wasm/graphite/Makefile",
238*2d1272b8SAndroid Build Coastguard Worker  "src/wasm/graphite/shape.cc",
239*2d1272b8SAndroid Build Coastguard Worker  "src/wasm/rust/harfbuzz-wasm/Cargo.toml",
240*2d1272b8SAndroid Build Coastguard Worker  "src/wasm/rust/harfbuzz-wasm/src/lib.rs",
241*2d1272b8SAndroid Build Coastguard Worker  "src/wasm/sample/c/Makefile",
242*2d1272b8SAndroid Build Coastguard Worker  "src/wasm/sample/c/shape-fallback.cc",
243*2d1272b8SAndroid Build Coastguard Worker  "src/wasm/sample/c/shape-ot.cc",
244*2d1272b8SAndroid Build Coastguard Worker  "src/wasm/sample/rust/hello-wasm/Cargo.toml",
245*2d1272b8SAndroid Build Coastguard Worker  "src/wasm/sample/rust/hello-wasm/src/lib.rs",
246*2d1272b8SAndroid Build Coastguard Worker  "subprojects/.gitignore",
247*2d1272b8SAndroid Build Coastguard Worker  "subprojects/cairo.wrap",
248*2d1272b8SAndroid Build Coastguard Worker  "subprojects/freetype2.wrap",
249*2d1272b8SAndroid Build Coastguard Worker  "subprojects/glib.wrap",
250*2d1272b8SAndroid Build Coastguard Worker  "subprojects/google-benchmark.wrap",
251*2d1272b8SAndroid Build Coastguard Worker  "subprojects/packagefiles/ragel/meson.build",
252*2d1272b8SAndroid Build Coastguard Worker  "subprojects/ragel.wrap",
253*2d1272b8SAndroid Build Coastguard Worker  "util/meson.build",
254*2d1272b8SAndroid Build Coastguard Worker  "util/test-hb-subset-parsing.c",
255*2d1272b8SAndroid Build Coastguard Worker]
256*2d1272b8SAndroid Build Coastguard Worker
257*2d1272b8SAndroid Build Coastguard Workerclass CommentType(Enum):
258*2d1272b8SAndroid Build Coastguard Worker  C_STYLE_BLOCK = 1  # /* ... */
259*2d1272b8SAndroid Build Coastguard Worker  C_STYLE_BLOCK_AS_LINE = 2  # /* ... */ but uses multiple lines of block comments.
260*2d1272b8SAndroid Build Coastguard Worker  C_STYLE_LINE = 3 # // ...
261*2d1272b8SAndroid Build Coastguard Worker  SCRIPT_STYLE_HASH = 4 #  # ...
262*2d1272b8SAndroid Build Coastguard Worker  OPENTYPE_NAME = 5
263*2d1272b8SAndroid Build Coastguard Worker  OPENTYPE_COLLECTION_NAME = 6
264*2d1272b8SAndroid Build Coastguard Worker  UNKNOWN = 10000
265*2d1272b8SAndroid Build Coastguard Worker
266*2d1272b8SAndroid Build Coastguard Worker
267*2d1272b8SAndroid Build Coastguard Worker# Helper function of showing error message and immediate exit.
268*2d1272b8SAndroid Build Coastguard Workerdef fatal(msg: str):
269*2d1272b8SAndroid Build Coastguard Worker  sys.stderr.write(str(msg))
270*2d1272b8SAndroid Build Coastguard Worker  sys.stderr.write("\n")
271*2d1272b8SAndroid Build Coastguard Worker  sys.exit(1)
272*2d1272b8SAndroid Build Coastguard Worker
273*2d1272b8SAndroid Build Coastguard Worker
274*2d1272b8SAndroid Build Coastguard Workerdef warn(msg: str):
275*2d1272b8SAndroid Build Coastguard Worker  sys.stderr.write(str(msg))
276*2d1272b8SAndroid Build Coastguard Worker  sys.stderr.write("\n")
277*2d1272b8SAndroid Build Coastguard Worker
278*2d1272b8SAndroid Build Coastguard Workerdef debug(msg: str):
279*2d1272b8SAndroid Build Coastguard Worker  # sys.stderr.write(str(msg))
280*2d1272b8SAndroid Build Coastguard Worker  # sys.stderr.write("\n")
281*2d1272b8SAndroid Build Coastguard Worker  pass
282*2d1272b8SAndroid Build Coastguard Worker
283*2d1272b8SAndroid Build Coastguard Worker
284*2d1272b8SAndroid Build Coastguard Workerdef cleanup_and_join(out_lines: Sequence[str]):
285*2d1272b8SAndroid Build Coastguard Worker  while not out_lines[-1].strip():
286*2d1272b8SAndroid Build Coastguard Worker    out_lines.pop(-1)
287*2d1272b8SAndroid Build Coastguard Worker
288*2d1272b8SAndroid Build Coastguard Worker  # If all lines starts from empty space, strip it out.
289*2d1272b8SAndroid Build Coastguard Worker  while all([len(x) == 0 or x[0] == ' ' for x in out_lines]):
290*2d1272b8SAndroid Build Coastguard Worker    out_lines = [x[1:] for x in out_lines]
291*2d1272b8SAndroid Build Coastguard Worker
292*2d1272b8SAndroid Build Coastguard Worker  if not out_lines:
293*2d1272b8SAndroid Build Coastguard Worker    fatal("Failed to get copyright info")
294*2d1272b8SAndroid Build Coastguard Worker  return "\n".join(out_lines)
295*2d1272b8SAndroid Build Coastguard Worker
296*2d1272b8SAndroid Build Coastguard Worker
297*2d1272b8SAndroid Build Coastguard Workerdef get_comment_type(copyright_line: str, path_str: str) -> CommentType:
298*2d1272b8SAndroid Build Coastguard Worker  # vms_make.com contains multiple copyright header as a string constants.
299*2d1272b8SAndroid Build Coastguard Worker  if copyright_line.startswith("#"):
300*2d1272b8SAndroid Build Coastguard Worker    return CommentType.SCRIPT_STYLE_HASH
301*2d1272b8SAndroid Build Coastguard Worker  if copyright_line.startswith("//"):
302*2d1272b8SAndroid Build Coastguard Worker    return CommentType.C_STYLE_LINE
303*2d1272b8SAndroid Build Coastguard Worker  return CommentType.C_STYLE_BLOCK
304*2d1272b8SAndroid Build Coastguard Worker
305*2d1272b8SAndroid Build Coastguard Workerdef extract_copyright_font(path_str: str) -> str:
306*2d1272b8SAndroid Build Coastguard Worker  path = Path(path_str)
307*2d1272b8SAndroid Build Coastguard Worker  if path.suffix in ['.ttf', '.otf', '.dfont']:
308*2d1272b8SAndroid Build Coastguard Worker    return extract_from_opentype_name(path, 0)
309*2d1272b8SAndroid Build Coastguard Worker  elif path.suffix in ['.ttc', '.otc']:
310*2d1272b8SAndroid Build Coastguard Worker    return extract_from_opentype_collection_name(path)
311*2d1272b8SAndroid Build Coastguard Worker
312*2d1272b8SAndroid Build Coastguard Worker
313*2d1272b8SAndroid Build Coastguard Worker# Extract copyright notice and returns next index.
314*2d1272b8SAndroid Build Coastguard Workerdef extract_copyright_at(lines: Sequence[str], i: int, path: str) -> Tuple[str, int]:
315*2d1272b8SAndroid Build Coastguard Worker  commentType = get_comment_type(lines[i], path)
316*2d1272b8SAndroid Build Coastguard Worker
317*2d1272b8SAndroid Build Coastguard Worker  if commentType == CommentType.C_STYLE_BLOCK:
318*2d1272b8SAndroid Build Coastguard Worker    return extract_from_c_style_block_at(lines, i, path)
319*2d1272b8SAndroid Build Coastguard Worker  elif commentType == CommentType.C_STYLE_LINE:
320*2d1272b8SAndroid Build Coastguard Worker    return extract_from_c_style_lines_at(lines, i, path)
321*2d1272b8SAndroid Build Coastguard Worker  elif commentType == CommentType.SCRIPT_STYLE_HASH:
322*2d1272b8SAndroid Build Coastguard Worker    return extract_from_script_hash_at(lines, i, path)
323*2d1272b8SAndroid Build Coastguard Worker  else:
324*2d1272b8SAndroid Build Coastguard Worker    fatal("Uknown comment style: %s" % lines[i])
325*2d1272b8SAndroid Build Coastguard Worker
326*2d1272b8SAndroid Build Coastguard Workerdef extract_from_opentype_collection_name(path: str) -> str:
327*2d1272b8SAndroid Build Coastguard Worker
328*2d1272b8SAndroid Build Coastguard Worker  with open(path, mode="rb") as f:
329*2d1272b8SAndroid Build Coastguard Worker    head = f.read(12)
330*2d1272b8SAndroid Build Coastguard Worker
331*2d1272b8SAndroid Build Coastguard Worker  if head[0:4].decode() != 'ttcf':
332*2d1272b8SAndroid Build Coastguard Worker    fatal('Invalid magic number for TTC file: %s' % path)
333*2d1272b8SAndroid Build Coastguard Worker  numFonts = int.from_bytes(head[8:12], byteorder="big")
334*2d1272b8SAndroid Build Coastguard Worker
335*2d1272b8SAndroid Build Coastguard Worker  licenses = set()
336*2d1272b8SAndroid Build Coastguard Worker  for i in range(0, numFonts):
337*2d1272b8SAndroid Build Coastguard Worker    license = extract_from_opentype_name(path, i)
338*2d1272b8SAndroid Build Coastguard Worker    licenses.add(license)
339*2d1272b8SAndroid Build Coastguard Worker
340*2d1272b8SAndroid Build Coastguard Worker  return '\n\n'.join(licenses)
341*2d1272b8SAndroid Build Coastguard Worker
342*2d1272b8SAndroid Build Coastguard Workerdef extract_from_opentype_name(path: str, index: int) -> str:
343*2d1272b8SAndroid Build Coastguard Worker
344*2d1272b8SAndroid Build Coastguard Worker  def get_preferred_name(nameID: int, ttf):
345*2d1272b8SAndroid Build Coastguard Worker    def get_score(platID: int, encID: int):
346*2d1272b8SAndroid Build Coastguard Worker      if platID == 3 and encID == 10:
347*2d1272b8SAndroid Build Coastguard Worker        return 0
348*2d1272b8SAndroid Build Coastguard Worker      elif platID == 0 and encID == 6:
349*2d1272b8SAndroid Build Coastguard Worker        return 1
350*2d1272b8SAndroid Build Coastguard Worker      elif platID == 0 and encID == 4:
351*2d1272b8SAndroid Build Coastguard Worker        return 2
352*2d1272b8SAndroid Build Coastguard Worker      elif platID == 3 and encID == 1:
353*2d1272b8SAndroid Build Coastguard Worker        return 3
354*2d1272b8SAndroid Build Coastguard Worker      elif platID == 0 and encID == 3:
355*2d1272b8SAndroid Build Coastguard Worker        return 4
356*2d1272b8SAndroid Build Coastguard Worker      elif platID == 0 and encID == 2:
357*2d1272b8SAndroid Build Coastguard Worker        return 5
358*2d1272b8SAndroid Build Coastguard Worker      elif platID == 0 and encID == 1:
359*2d1272b8SAndroid Build Coastguard Worker        return 6
360*2d1272b8SAndroid Build Coastguard Worker      elif platID == 0 and encID == 0:
361*2d1272b8SAndroid Build Coastguard Worker        return 7
362*2d1272b8SAndroid Build Coastguard Worker      else:
363*2d1272b8SAndroid Build Coastguard Worker        return 10000
364*2d1272b8SAndroid Build Coastguard Worker
365*2d1272b8SAndroid Build Coastguard Worker    best_score = 1000000
366*2d1272b8SAndroid Build Coastguard Worker    best_name = None
367*2d1272b8SAndroid Build Coastguard Worker
368*2d1272b8SAndroid Build Coastguard Worker    if 'name' not in ttf:
369*2d1272b8SAndroid Build Coastguard Worker      return None
370*2d1272b8SAndroid Build Coastguard Worker
371*2d1272b8SAndroid Build Coastguard Worker    for name in ttf['name'].names:
372*2d1272b8SAndroid Build Coastguard Worker      if name.nameID != nameID:
373*2d1272b8SAndroid Build Coastguard Worker        continue
374*2d1272b8SAndroid Build Coastguard Worker
375*2d1272b8SAndroid Build Coastguard Worker      score = get_score(name.platformID, name.platEncID)
376*2d1272b8SAndroid Build Coastguard Worker      if score < best_score:
377*2d1272b8SAndroid Build Coastguard Worker        best_score = score
378*2d1272b8SAndroid Build Coastguard Worker        best_name = name
379*2d1272b8SAndroid Build Coastguard Worker
380*2d1272b8SAndroid Build Coastguard Worker    return best_name
381*2d1272b8SAndroid Build Coastguard Worker
382*2d1272b8SAndroid Build Coastguard Worker  def get_notice_from_cff(ttf):
383*2d1272b8SAndroid Build Coastguard Worker    if 'CFF ' not in ttf:
384*2d1272b8SAndroid Build Coastguard Worker      return None
385*2d1272b8SAndroid Build Coastguard Worker
386*2d1272b8SAndroid Build Coastguard Worker    # Looks like there is no way of getting Notice line in CFF table.
387*2d1272b8SAndroid Build Coastguard Worker    # Use the line that has "Copyright" in the string pool.
388*2d1272b8SAndroid Build Coastguard Worker    cff = ttf['CFF '].cff
389*2d1272b8SAndroid Build Coastguard Worker    for string in cff.strings:
390*2d1272b8SAndroid Build Coastguard Worker      if 'Copyright' in string:
391*2d1272b8SAndroid Build Coastguard Worker        return string
392*2d1272b8SAndroid Build Coastguard Worker    return None
393*2d1272b8SAndroid Build Coastguard Worker
394*2d1272b8SAndroid Build Coastguard Worker  with contextlib.closing(ttLib.TTFont(path, 0, fontNumber=index)) as ttf:
395*2d1272b8SAndroid Build Coastguard Worker    copyright = get_preferred_name(0, ttf)
396*2d1272b8SAndroid Build Coastguard Worker    if not copyright:
397*2d1272b8SAndroid Build Coastguard Worker      copyright = get_notice_from_cff(ttf)
398*2d1272b8SAndroid Build Coastguard Worker    if not copyright:
399*2d1272b8SAndroid Build Coastguard Worker      return None
400*2d1272b8SAndroid Build Coastguard Worker
401*2d1272b8SAndroid Build Coastguard Worker    license_description = get_preferred_name(13, ttf)
402*2d1272b8SAndroid Build Coastguard Worker
403*2d1272b8SAndroid Build Coastguard Worker    if license_description:
404*2d1272b8SAndroid Build Coastguard Worker      copyright = str(copyright) + "\n\n" + str(license_description)
405*2d1272b8SAndroid Build Coastguard Worker    else:
406*2d1272b8SAndroid Build Coastguard Worker      copyright = str(copyright)
407*2d1272b8SAndroid Build Coastguard Worker
408*2d1272b8SAndroid Build Coastguard Worker    license_url = get_preferred_name(14, ttf)
409*2d1272b8SAndroid Build Coastguard Worker
410*2d1272b8SAndroid Build Coastguard Worker    if license_url:
411*2d1272b8SAndroid Build Coastguard Worker      copyright = str(copyright) + "\n\n" + str(license_url)
412*2d1272b8SAndroid Build Coastguard Worker    else:
413*2d1272b8SAndroid Build Coastguard Worker      copyright = str(copyright)
414*2d1272b8SAndroid Build Coastguard Worker
415*2d1272b8SAndroid Build Coastguard Worker    return copyright
416*2d1272b8SAndroid Build Coastguard Worker
417*2d1272b8SAndroid Build Coastguard Workerdef extract_from_c_style_lines_at(
418*2d1272b8SAndroid Build Coastguard Worker    lines: Sequence[str], i: int, path: str) -> Tuple[str, int]:
419*2d1272b8SAndroid Build Coastguard Worker  def is_copyright_end(line):
420*2d1272b8SAndroid Build Coastguard Worker    if line.startswith("//"):
421*2d1272b8SAndroid Build Coastguard Worker      return False
422*2d1272b8SAndroid Build Coastguard Worker    else:
423*2d1272b8SAndroid Build Coastguard Worker      return True
424*2d1272b8SAndroid Build Coastguard Worker  start = i
425*2d1272b8SAndroid Build Coastguard Worker  while i < len(lines):
426*2d1272b8SAndroid Build Coastguard Worker    if is_copyright_end(lines[i]):
427*2d1272b8SAndroid Build Coastguard Worker      break
428*2d1272b8SAndroid Build Coastguard Worker    i += 1
429*2d1272b8SAndroid Build Coastguard Worker  end = i
430*2d1272b8SAndroid Build Coastguard Worker
431*2d1272b8SAndroid Build Coastguard Worker  if start == end:
432*2d1272b8SAndroid Build Coastguard Worker    fatal("Failed to get copyright info")
433*2d1272b8SAndroid Build Coastguard Worker
434*2d1272b8SAndroid Build Coastguard Worker  out_lines = []
435*2d1272b8SAndroid Build Coastguard Worker  for line in lines[start:end]:
436*2d1272b8SAndroid Build Coastguard Worker    if line.startswith("//# "):  # Andorid.bp uses //# style
437*2d1272b8SAndroid Build Coastguard Worker      out_lines.append(line[4:])
438*2d1272b8SAndroid Build Coastguard Worker    elif line.startswith("//#"):  # Andorid.bp uses //# style
439*2d1272b8SAndroid Build Coastguard Worker      out_lines.append(line[3:])
440*2d1272b8SAndroid Build Coastguard Worker    elif line.startswith("// "):
441*2d1272b8SAndroid Build Coastguard Worker      out_lines.append(line[3:])
442*2d1272b8SAndroid Build Coastguard Worker    elif line == "//":
443*2d1272b8SAndroid Build Coastguard Worker      out_lines.append(line[2:])
444*2d1272b8SAndroid Build Coastguard Worker    else:
445*2d1272b8SAndroid Build Coastguard Worker      out_lines.append(line)
446*2d1272b8SAndroid Build Coastguard Worker
447*2d1272b8SAndroid Build Coastguard Worker  return (cleanup_and_join(out_lines), i + 1)
448*2d1272b8SAndroid Build Coastguard Worker
449*2d1272b8SAndroid Build Coastguard Worker
450*2d1272b8SAndroid Build Coastguard Workerdef extract_from_script_hash_at(
451*2d1272b8SAndroid Build Coastguard Worker    lines: Sequence[str], i: int, path: str) -> Tuple[str, int]:
452*2d1272b8SAndroid Build Coastguard Worker  if lines[i].strip()[0] != "#":
453*2d1272b8SAndroid Build Coastguard Worker    return (None, i + 1)
454*2d1272b8SAndroid Build Coastguard Worker  def is_copyright_end(lines: str, i: int) -> bool:
455*2d1272b8SAndroid Build Coastguard Worker    if "#" not in lines[i]:
456*2d1272b8SAndroid Build Coastguard Worker      return True
457*2d1272b8SAndroid Build Coastguard Worker    # treat double spacing as end of license header
458*2d1272b8SAndroid Build Coastguard Worker    if lines[i] == "#" and lines[i+1] == "#":
459*2d1272b8SAndroid Build Coastguard Worker      return True
460*2d1272b8SAndroid Build Coastguard Worker    return False
461*2d1272b8SAndroid Build Coastguard Worker
462*2d1272b8SAndroid Build Coastguard Worker  start = i
463*2d1272b8SAndroid Build Coastguard Worker  while i < len(lines):
464*2d1272b8SAndroid Build Coastguard Worker    if is_copyright_end(lines, i):
465*2d1272b8SAndroid Build Coastguard Worker      break
466*2d1272b8SAndroid Build Coastguard Worker    i += 1
467*2d1272b8SAndroid Build Coastguard Worker  end = i
468*2d1272b8SAndroid Build Coastguard Worker
469*2d1272b8SAndroid Build Coastguard Worker  if start == end:
470*2d1272b8SAndroid Build Coastguard Worker    fatal("Failed to get copyright info")
471*2d1272b8SAndroid Build Coastguard Worker
472*2d1272b8SAndroid Build Coastguard Worker  out_lines = []
473*2d1272b8SAndroid Build Coastguard Worker  for line in lines[start:end]:
474*2d1272b8SAndroid Build Coastguard Worker    if line.startswith("# "):
475*2d1272b8SAndroid Build Coastguard Worker      out_lines.append(line[2:])
476*2d1272b8SAndroid Build Coastguard Worker    elif line == "#":
477*2d1272b8SAndroid Build Coastguard Worker      out_lines.append(line[1:])
478*2d1272b8SAndroid Build Coastguard Worker    else:
479*2d1272b8SAndroid Build Coastguard Worker      out_lines.append(line)
480*2d1272b8SAndroid Build Coastguard Worker
481*2d1272b8SAndroid Build Coastguard Worker  return (cleanup_and_join(out_lines), i + 1)
482*2d1272b8SAndroid Build Coastguard Worker
483*2d1272b8SAndroid Build Coastguard Worker
484*2d1272b8SAndroid Build Coastguard Workerdef extract_from_c_style_block_at(
485*2d1272b8SAndroid Build Coastguard Worker    lines: Sequence[str], i: int, path: str) -> Tuple[str, int]:
486*2d1272b8SAndroid Build Coastguard Worker
487*2d1272b8SAndroid Build Coastguard Worker  def is_copyright_end(lines: str, i: int) -> bool:
488*2d1272b8SAndroid Build Coastguard Worker    if "*/" in lines[i]:
489*2d1272b8SAndroid Build Coastguard Worker      return True
490*2d1272b8SAndroid Build Coastguard Worker    if lines[i] == " *" and lines[i + 1] == " *":
491*2d1272b8SAndroid Build Coastguard Worker      return True
492*2d1272b8SAndroid Build Coastguard Worker    if lines[i] == "" and lines[i + 1] == "":
493*2d1272b8SAndroid Build Coastguard Worker      return True
494*2d1272b8SAndroid Build Coastguard Worker    return False
495*2d1272b8SAndroid Build Coastguard Worker
496*2d1272b8SAndroid Build Coastguard Worker  start = i
497*2d1272b8SAndroid Build Coastguard Worker  i += 1 # include at least one line
498*2d1272b8SAndroid Build Coastguard Worker  while i < len(lines):
499*2d1272b8SAndroid Build Coastguard Worker    if is_copyright_end(lines, i):
500*2d1272b8SAndroid Build Coastguard Worker      break
501*2d1272b8SAndroid Build Coastguard Worker    i += 1
502*2d1272b8SAndroid Build Coastguard Worker  end = i + 1
503*2d1272b8SAndroid Build Coastguard Worker
504*2d1272b8SAndroid Build Coastguard Worker  out_lines = []
505*2d1272b8SAndroid Build Coastguard Worker  for line in lines[start:end]:
506*2d1272b8SAndroid Build Coastguard Worker    clean_line = line
507*2d1272b8SAndroid Build Coastguard Worker
508*2d1272b8SAndroid Build Coastguard Worker    # Strip begining "/*" chars
509*2d1272b8SAndroid Build Coastguard Worker    if clean_line.startswith("/* "):
510*2d1272b8SAndroid Build Coastguard Worker      clean_line = clean_line[3:]
511*2d1272b8SAndroid Build Coastguard Worker    if clean_line == "/*":
512*2d1272b8SAndroid Build Coastguard Worker      clean_line = clean_line[2:]
513*2d1272b8SAndroid Build Coastguard Worker
514*2d1272b8SAndroid Build Coastguard Worker    # Strip ending "*/" chars
515*2d1272b8SAndroid Build Coastguard Worker    if clean_line.endswith(" */"):
516*2d1272b8SAndroid Build Coastguard Worker      clean_line = clean_line[:-3]
517*2d1272b8SAndroid Build Coastguard Worker    if clean_line.endswith("*/"):
518*2d1272b8SAndroid Build Coastguard Worker      clean_line = clean_line[:-2]
519*2d1272b8SAndroid Build Coastguard Worker
520*2d1272b8SAndroid Build Coastguard Worker    # Strip starting " *" chars
521*2d1272b8SAndroid Build Coastguard Worker    if clean_line.startswith(" * "):
522*2d1272b8SAndroid Build Coastguard Worker      clean_line = clean_line[3:]
523*2d1272b8SAndroid Build Coastguard Worker    if clean_line == " *":
524*2d1272b8SAndroid Build Coastguard Worker      clean_line = clean_line[2:]
525*2d1272b8SAndroid Build Coastguard Worker
526*2d1272b8SAndroid Build Coastguard Worker    # hb-aots-tester.cpp has underline separater which can be dropped.
527*2d1272b8SAndroid Build Coastguard Worker    if path.endswith("test/shape/data/aots/hb-aots-tester.cpp"):
528*2d1272b8SAndroid Build Coastguard Worker      clean_line = clean_line.replace("_", "")
529*2d1272b8SAndroid Build Coastguard Worker
530*2d1272b8SAndroid Build Coastguard Worker    # Strip trailing spaces
531*2d1272b8SAndroid Build Coastguard Worker    clean_line = clean_line.rstrip()
532*2d1272b8SAndroid Build Coastguard Worker
533*2d1272b8SAndroid Build Coastguard Worker    out_lines.append(clean_line)
534*2d1272b8SAndroid Build Coastguard Worker
535*2d1272b8SAndroid Build Coastguard Worker  return (cleanup_and_join(out_lines), i + 1)
536*2d1272b8SAndroid Build Coastguard Worker
537*2d1272b8SAndroid Build Coastguard Worker
538*2d1272b8SAndroid Build Coastguard Worker# Returns true if the line shows the start of copyright notice.
539*2d1272b8SAndroid Build Coastguard Workerdef is_copyright_line(line: str, path: str) -> bool:
540*2d1272b8SAndroid Build Coastguard Worker  if "Copyright" not in line:
541*2d1272b8SAndroid Build Coastguard Worker    return False
542*2d1272b8SAndroid Build Coastguard Worker
543*2d1272b8SAndroid Build Coastguard Worker  # For avoiding unexpected mismatches, exclude quoted Copyright string.
544*2d1272b8SAndroid Build Coastguard Worker  if "`Copyright'" in line:
545*2d1272b8SAndroid Build Coastguard Worker    return False
546*2d1272b8SAndroid Build Coastguard Worker  if "\"Copyright\"" in line:
547*2d1272b8SAndroid Build Coastguard Worker    return False
548*2d1272b8SAndroid Build Coastguard Worker
549*2d1272b8SAndroid Build Coastguard Worker  if "OpCode_Copyright" in line:
550*2d1272b8SAndroid Build Coastguard Worker    return False
551*2d1272b8SAndroid Build Coastguard Worker
552*2d1272b8SAndroid Build Coastguard Worker  if path.endswith("src/hb-ot-name.h") and "HB_OT_NAME_ID_COPYRIGHT" in line:
553*2d1272b8SAndroid Build Coastguard Worker    return False
554*2d1272b8SAndroid Build Coastguard Worker
555*2d1272b8SAndroid Build Coastguard Worker  return True
556*2d1272b8SAndroid Build Coastguard Worker
557*2d1272b8SAndroid Build Coastguard Workerdef assert_mandatory_copyright(path_str: str):
558*2d1272b8SAndroid Build Coastguard Worker  path = Path(path_str)
559*2d1272b8SAndroid Build Coastguard Worker  toplevel_dir = str(path).split(os.sep)[0]
560*2d1272b8SAndroid Build Coastguard Worker
561*2d1272b8SAndroid Build Coastguard Worker  if toplevel_dir in IGNORE_DIR_IF_NO_COPYRIGHT:
562*2d1272b8SAndroid Build Coastguard Worker    return
563*2d1272b8SAndroid Build Coastguard Worker
564*2d1272b8SAndroid Build Coastguard Worker  fatal("%s does not contain Copyright line" % path)
565*2d1272b8SAndroid Build Coastguard Worker
566*2d1272b8SAndroid Build Coastguard Worker
567*2d1272b8SAndroid Build Coastguard Worker# Extract the copyright notice and put it into copyrights arg.
568*2d1272b8SAndroid Build Coastguard Workerdef do_file(path: str, copyrights: set, no_copyright_files: set):
569*2d1272b8SAndroid Build Coastguard Worker  raw = Path(path).read_bytes()
570*2d1272b8SAndroid Build Coastguard Worker  basename = os.path.basename(path)
571*2d1272b8SAndroid Build Coastguard Worker  dirname = os.path.dirname(path)
572*2d1272b8SAndroid Build Coastguard Worker
573*2d1272b8SAndroid Build Coastguard Worker  is_font = (dirname.endswith('./test/fuzzing/fonts') or
574*2d1272b8SAndroid Build Coastguard Worker             Path(path).suffix in ['.ttf', '.otf', '.dfont', '.ttc', '.otc'])
575*2d1272b8SAndroid Build Coastguard Worker
576*2d1272b8SAndroid Build Coastguard Worker  if is_font:
577*2d1272b8SAndroid Build Coastguard Worker    notice = extract_copyright_font(path)
578*2d1272b8SAndroid Build Coastguard Worker    if not notice:
579*2d1272b8SAndroid Build Coastguard Worker      assert_mandatory_copyright(path)
580*2d1272b8SAndroid Build Coastguard Worker      return
581*2d1272b8SAndroid Build Coastguard Worker
582*2d1272b8SAndroid Build Coastguard Worker    if not notice in copyrights:
583*2d1272b8SAndroid Build Coastguard Worker      copyrights[notice] = []
584*2d1272b8SAndroid Build Coastguard Worker    copyrights[notice].append(path)
585*2d1272b8SAndroid Build Coastguard Worker  else:
586*2d1272b8SAndroid Build Coastguard Worker    try:
587*2d1272b8SAndroid Build Coastguard Worker      content = raw.decode("utf-8")
588*2d1272b8SAndroid Build Coastguard Worker    except UnicodeDecodeError:
589*2d1272b8SAndroid Build Coastguard Worker      content = raw.decode("iso-8859-1")
590*2d1272b8SAndroid Build Coastguard Worker
591*2d1272b8SAndroid Build Coastguard Worker    if not "Copyright" in content:
592*2d1272b8SAndroid Build Coastguard Worker      if path in no_copyright_files:
593*2d1272b8SAndroid Build Coastguard Worker        no_copyright_files.remove(path)
594*2d1272b8SAndroid Build Coastguard Worker      else:
595*2d1272b8SAndroid Build Coastguard Worker        assert_mandatory_copyright(path)
596*2d1272b8SAndroid Build Coastguard Worker      return
597*2d1272b8SAndroid Build Coastguard Worker
598*2d1272b8SAndroid Build Coastguard Worker    lines = content.splitlines()
599*2d1272b8SAndroid Build Coastguard Worker
600*2d1272b8SAndroid Build Coastguard Worker    # The COPYING in the in-house dir has full OFL license with description.
601*2d1272b8SAndroid Build Coastguard Worker    # Use the OFL license description body.
602*2d1272b8SAndroid Build Coastguard Worker    if path.endswith("test/shape/data/in-house/COPYING") or path.endswith("test/COPYING"):
603*2d1272b8SAndroid Build Coastguard Worker      notice = cleanup_and_join(lines[9:])
604*2d1272b8SAndroid Build Coastguard Worker      copyrights.setdefault(notice, [])
605*2d1272b8SAndroid Build Coastguard Worker      copyrights[notice].append(path)
606*2d1272b8SAndroid Build Coastguard Worker      return
607*2d1272b8SAndroid Build Coastguard Worker
608*2d1272b8SAndroid Build Coastguard Worker    # The COPYING in the top dir has MIT-Modern-Variant license with description.
609*2d1272b8SAndroid Build Coastguard Worker    # Use the entire file as a license notice.
610*2d1272b8SAndroid Build Coastguard Worker    if path.endswith("COPYING") and str(Path(path)) == 'COPYING':
611*2d1272b8SAndroid Build Coastguard Worker      notice = cleanup_and_join(lines)
612*2d1272b8SAndroid Build Coastguard Worker      copyrights.setdefault(notice, [])
613*2d1272b8SAndroid Build Coastguard Worker      copyrights[notice].append(path)
614*2d1272b8SAndroid Build Coastguard Worker      return
615*2d1272b8SAndroid Build Coastguard Worker
616*2d1272b8SAndroid Build Coastguard Worker    i = 0
617*2d1272b8SAndroid Build Coastguard Worker    license_found = False
618*2d1272b8SAndroid Build Coastguard Worker    while i < len(lines):
619*2d1272b8SAndroid Build Coastguard Worker      if is_copyright_line(lines[i], path):
620*2d1272b8SAndroid Build Coastguard Worker        (notice, nexti) = extract_copyright_at(lines, i, path)
621*2d1272b8SAndroid Build Coastguard Worker        if notice:
622*2d1272b8SAndroid Build Coastguard Worker          copyrights.setdefault(notice, [])
623*2d1272b8SAndroid Build Coastguard Worker          copyrights[notice].append(path)
624*2d1272b8SAndroid Build Coastguard Worker          license_found = True
625*2d1272b8SAndroid Build Coastguard Worker
626*2d1272b8SAndroid Build Coastguard Worker        i = nexti
627*2d1272b8SAndroid Build Coastguard Worker      else:
628*2d1272b8SAndroid Build Coastguard Worker        i += 1
629*2d1272b8SAndroid Build Coastguard Worker
630*2d1272b8SAndroid Build Coastguard Worker    if not license_found:
631*2d1272b8SAndroid Build Coastguard Worker      assert_mandatory_copyright(path)
632*2d1272b8SAndroid Build Coastguard Worker
633*2d1272b8SAndroid Build Coastguard Workerdef do_check(path, format):
634*2d1272b8SAndroid Build Coastguard Worker  if not path.endswith('/'): # make sure the path ends with slash
635*2d1272b8SAndroid Build Coastguard Worker    path = path + '/'
636*2d1272b8SAndroid Build Coastguard Worker
637*2d1272b8SAndroid Build Coastguard Worker  file_to_ignore = set([os.path.join(path, x) for x in IGNORE_FILE_NAME])
638*2d1272b8SAndroid Build Coastguard Worker  no_copyright_files = set([os.path.join(path, x) for x in NO_COPYRIGHT_FILES])
639*2d1272b8SAndroid Build Coastguard Worker  copyrights = {}
640*2d1272b8SAndroid Build Coastguard Worker
641*2d1272b8SAndroid Build Coastguard Worker  for directory, sub_directories, filenames in os.walk(path):
642*2d1272b8SAndroid Build Coastguard Worker    # skip .git directory
643*2d1272b8SAndroid Build Coastguard Worker    if ".git" in sub_directories:
644*2d1272b8SAndroid Build Coastguard Worker      sub_directories.remove(".git")
645*2d1272b8SAndroid Build Coastguard Worker
646*2d1272b8SAndroid Build Coastguard Worker    for fname in filenames:
647*2d1272b8SAndroid Build Coastguard Worker      fpath = os.path.join(directory, fname)
648*2d1272b8SAndroid Build Coastguard Worker      if fpath in file_to_ignore:
649*2d1272b8SAndroid Build Coastguard Worker        file_to_ignore.remove(fpath)
650*2d1272b8SAndroid Build Coastguard Worker        continue
651*2d1272b8SAndroid Build Coastguard Worker
652*2d1272b8SAndroid Build Coastguard Worker      do_file(fpath, copyrights, no_copyright_files)
653*2d1272b8SAndroid Build Coastguard Worker
654*2d1272b8SAndroid Build Coastguard Worker  if len(file_to_ignore) != 0:
655*2d1272b8SAndroid Build Coastguard Worker    fatal("Following files are listed in IGNORE_FILE_NAME but doesn't exists,.\n"
656*2d1272b8SAndroid Build Coastguard Worker          + "\n".join(file_to_ignore))
657*2d1272b8SAndroid Build Coastguard Worker
658*2d1272b8SAndroid Build Coastguard Worker  if len(no_copyright_files) != 0:
659*2d1272b8SAndroid Build Coastguard Worker    fatal("Following files are listed in NO_COPYRIGHT_FILES but doesn't exists.\n"
660*2d1272b8SAndroid Build Coastguard Worker          + "\n".join(no_copyright_files))
661*2d1272b8SAndroid Build Coastguard Worker
662*2d1272b8SAndroid Build Coastguard Worker  if format == Format.notice:
663*2d1272b8SAndroid Build Coastguard Worker    print_notice(copyrights, False)
664*2d1272b8SAndroid Build Coastguard Worker  elif format == Format.notice_with_filename:
665*2d1272b8SAndroid Build Coastguard Worker    print_notice(copyrights, True)
666*2d1272b8SAndroid Build Coastguard Worker  elif format == Format.html:
667*2d1272b8SAndroid Build Coastguard Worker    print_html(copyrights)
668*2d1272b8SAndroid Build Coastguard Worker  elif format == Format.json:
669*2d1272b8SAndroid Build Coastguard Worker    print_json(copyrights)
670*2d1272b8SAndroid Build Coastguard Worker
671*2d1272b8SAndroid Build Coastguard Workerdef print_html(copyrights):
672*2d1272b8SAndroid Build Coastguard Worker  print('<html>')
673*2d1272b8SAndroid Build Coastguard Worker  print("""
674*2d1272b8SAndroid Build Coastguard Worker  <head>
675*2d1272b8SAndroid Build Coastguard Worker    <style>
676*2d1272b8SAndroid Build Coastguard Worker      table {
677*2d1272b8SAndroid Build Coastguard Worker        font-family: monospace
678*2d1272b8SAndroid Build Coastguard Worker      }
679*2d1272b8SAndroid Build Coastguard Worker
680*2d1272b8SAndroid Build Coastguard Worker      table tr td {
681*2d1272b8SAndroid Build Coastguard Worker        padding: 10px 10px 10px 10px
682*2d1272b8SAndroid Build Coastguard Worker      }
683*2d1272b8SAndroid Build Coastguard Worker    </style>
684*2d1272b8SAndroid Build Coastguard Worker  </head>
685*2d1272b8SAndroid Build Coastguard Worker  """)
686*2d1272b8SAndroid Build Coastguard Worker  print('<body>')
687*2d1272b8SAndroid Build Coastguard Worker  print('<table border="1" style="border-collapse:collapse">')
688*2d1272b8SAndroid Build Coastguard Worker  for notice in sorted(copyrights.keys()):
689*2d1272b8SAndroid Build Coastguard Worker    files = sorted(copyrights[notice])
690*2d1272b8SAndroid Build Coastguard Worker
691*2d1272b8SAndroid Build Coastguard Worker    print('<tr>')
692*2d1272b8SAndroid Build Coastguard Worker    print('<td>')
693*2d1272b8SAndroid Build Coastguard Worker    print('<ul>')
694*2d1272b8SAndroid Build Coastguard Worker    for file in files:
695*2d1272b8SAndroid Build Coastguard Worker      print('<li>%s</li>' % file)
696*2d1272b8SAndroid Build Coastguard Worker    print('</ul>')
697*2d1272b8SAndroid Build Coastguard Worker    print('</td>')
698*2d1272b8SAndroid Build Coastguard Worker
699*2d1272b8SAndroid Build Coastguard Worker    print('<td>')
700*2d1272b8SAndroid Build Coastguard Worker    print('<p>%s</p>' % notice.replace('\n', '<br>'))
701*2d1272b8SAndroid Build Coastguard Worker    print('</td>')
702*2d1272b8SAndroid Build Coastguard Worker
703*2d1272b8SAndroid Build Coastguard Worker    print('</tr>')
704*2d1272b8SAndroid Build Coastguard Worker
705*2d1272b8SAndroid Build Coastguard Worker
706*2d1272b8SAndroid Build Coastguard Worker  print('</table>')
707*2d1272b8SAndroid Build Coastguard Worker  print('</body></html>')
708*2d1272b8SAndroid Build Coastguard Worker
709*2d1272b8SAndroid Build Coastguard Workerdef print_notice(copyrights, print_file):
710*2d1272b8SAndroid Build Coastguard Worker  # print the copyright in sorted order for stable output.
711*2d1272b8SAndroid Build Coastguard Worker  for notice in sorted(copyrights.keys()):
712*2d1272b8SAndroid Build Coastguard Worker    if print_file:
713*2d1272b8SAndroid Build Coastguard Worker      files = sorted(copyrights[notice])
714*2d1272b8SAndroid Build Coastguard Worker      print("\n".join(files))
715*2d1272b8SAndroid Build Coastguard Worker      print()
716*2d1272b8SAndroid Build Coastguard Worker    print(notice)
717*2d1272b8SAndroid Build Coastguard Worker    print()
718*2d1272b8SAndroid Build Coastguard Worker    print("-" * 67)
719*2d1272b8SAndroid Build Coastguard Worker    print()
720*2d1272b8SAndroid Build Coastguard Worker
721*2d1272b8SAndroid Build Coastguard Workerdef print_json(copyrights):
722*2d1272b8SAndroid Build Coastguard Worker  print(json.dumps(copyrights))
723*2d1272b8SAndroid Build Coastguard Worker
724*2d1272b8SAndroid Build Coastguard Workerclass Format(Enum):
725*2d1272b8SAndroid Build Coastguard Worker  notice = 'notice'
726*2d1272b8SAndroid Build Coastguard Worker  notice_with_filename = 'notice_with_filename'
727*2d1272b8SAndroid Build Coastguard Worker  html = 'html'
728*2d1272b8SAndroid Build Coastguard Worker  json = 'json'
729*2d1272b8SAndroid Build Coastguard Worker
730*2d1272b8SAndroid Build Coastguard Worker  def __str__(self):
731*2d1272b8SAndroid Build Coastguard Worker    return self.value
732*2d1272b8SAndroid Build Coastguard Worker
733*2d1272b8SAndroid Build Coastguard Workerdef main():
734*2d1272b8SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(description="Collect notice headers.")
735*2d1272b8SAndroid Build Coastguard Worker  parser.add_argument("--format", dest="format", type=Format, choices=list(Format),
736*2d1272b8SAndroid Build Coastguard Worker                      default=Format.notice, help="print filename before the license notice")
737*2d1272b8SAndroid Build Coastguard Worker  parser.add_argument("--target", dest="target", action='store',
738*2d1272b8SAndroid Build Coastguard Worker                      required=True, help="target directory to collect notice headers")
739*2d1272b8SAndroid Build Coastguard Worker  res = parser.parse_args()
740*2d1272b8SAndroid Build Coastguard Worker  do_check(res.target, res.format)
741*2d1272b8SAndroid Build Coastguard Worker
742*2d1272b8SAndroid Build Coastguard Workerif __name__ == "__main__":
743*2d1272b8SAndroid Build Coastguard Worker  main()
744*2d1272b8SAndroid Build Coastguard Worker
745