1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <cstdint>
16
17 #include "helper.h" // NOLINT(build/include)
18 #include "tiffio.h" // NOLINT(build/include)
19
20 using ::sapi::IsOk;
21 using ::testing::Eq;
22 using ::testing::IsTrue;
23 using ::testing::NotNull;
24
25 // sapi functions:
26 // TIFFOpen
27 // TIFFClose
28 // TIFFGetField
29 // TIFFSetField
30 // TIFFWriteCheck
31 // TIFFSetDirectory
32 // TIFFFreeDirectory
33 // TIFFWriteScanline
34 // TIFFWriteDirectory
35 // TIFFCreateDirectory
36 // TIFFReadEncodedTile
37 // TIFFReadEncodedStrip
38 // TIFFWriteEncodedTile
39 // TIFFWriteEncodedStrip
40 // TIFFDeferStrileArrayWriting
41 // TIFFForceStrileArrayWriting
42
43 namespace {
44
45 constexpr int kTileBufferSize = 256;
46 constexpr int kWidth = 1;
47 constexpr int kBps = 8;
48 constexpr int kRowsPerStrip = 1;
49 constexpr int kSamplePerPixel = 1;
50
TestWriting(const char * mode,int tiled,int height)51 void TestWriting(const char* mode, int tiled, int height) {
52 absl::StatusOr<std::string> status_or_path =
53 sapi::CreateNamedTempFileAndClose("defer_strile_writing.tif");
54 ASSERT_THAT(status_or_path, IsOk()) << "Could not create temp file";
55
56 std::string srcfile = sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(),
57 status_or_path.value());
58
59 absl::StatusOr<int> status_or_int;
60 absl::StatusOr<int64_t> status_or_long;
61 absl::StatusOr<TIFF*> status_or_tif;
62
63 TiffSapiSandbox sandbox("", srcfile);
64 ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
65
66 TiffApi api(&sandbox);
67 sapi::v::ConstCStr srcfile_var(srcfile.c_str());
68 sapi::v::ConstCStr mode_var(mode);
69
70 status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), mode_var.PtrBefore());
71 ASSERT_THAT(status_or_tif, IsOk()) << "Could not open " << srcfile;
72
73 sapi::v::RemotePtr tif(status_or_tif.value());
74 ASSERT_THAT(tif.GetValue(), NotNull())
75 << "Can't create test TIFF file " << srcfile;
76
77 status_or_int =
78 api.TIFFSetFieldU1(&tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
79 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
80 EXPECT_THAT(status_or_int.value(), IsTrue())
81 << "Can't set CompressionNone tag";
82
83 status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_IMAGEWIDTH, kWidth);
84 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
85 EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImageWidth tag";
86
87 status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_IMAGELENGTH, height);
88 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
89 EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImageLenght tag";
90
91 status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_BITSPERSAMPLE, kBps);
92 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
93 EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set BitsPerSample tag";
94
95 status_or_int =
96 api.TIFFSetFieldU1(&tif, TIFFTAG_SAMPLESPERPIXEL, kSamplePerPixel);
97 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
98 EXPECT_THAT(status_or_int.value(), IsTrue())
99 << "Can't set SamplesPerPixel tag";
100
101 status_or_int =
102 api.TIFFSetFieldU1(&tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
103 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
104 EXPECT_THAT(status_or_int.value(), IsTrue())
105 << "Can't set PlanarConfiguration tag";
106
107 if (tiled) {
108 status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_TILEWIDTH, 16);
109 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
110 EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set TileWidth tag";
111
112 status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_TILELENGTH, 16);
113 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
114 EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set TileLenght tag";
115 } else {
116 status_or_int =
117 api.TIFFSetFieldU1(&tif, TIFFTAG_ROWSPERSTRIP, kRowsPerStrip);
118 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
119 EXPECT_THAT(status_or_int.value(), IsTrue())
120 << "Can't set RowsPerStrip tag";
121 }
122
123 status_or_int = api.TIFFDeferStrileArrayWriting(&tif);
124 ASSERT_THAT(status_or_int, IsOk())
125 << "TIFFDeferStrileArrayWriting fatal error";
126 EXPECT_THAT(status_or_int.value(), IsTrue())
127 << "TIFFDeferStrileArrayWriting return unexpected value";
128
129 sapi::v::ConstCStr test_var("test");
130 status_or_int = api.TIFFWriteCheck(&tif, tiled, test_var.PtrBefore());
131 ASSERT_THAT(status_or_int, IsOk()) << "TIFFWriteCheck fatal error";
132 EXPECT_THAT(status_or_int.value(), IsTrue())
133 << "TIFFWriteCheck return unexpected value "
134 << "void test(" << mode << ", " << tiled << ", " << height << ")";
135
136 status_or_int = api.TIFFWriteDirectory(&tif);
137 ASSERT_THAT(status_or_int, IsOk())
138 << "TIFFDeferStrileArrayWriting fatal error";
139 EXPECT_THAT(status_or_int.value(), IsTrue())
140 << "TIFFDeferStrileArrayWriting return unexpected value";
141
142 // Create other directory
143 ASSERT_THAT(api.TIFFFreeDirectory(&tif), IsOk())
144 << "TIFFFreeDirectory fatal error";
145 ASSERT_THAT(api.TIFFCreateDirectory(&tif), IsOk())
146 << "TIFFCreateDirectory fatal error";
147
148 status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
149 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
150 EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set SubFileType tag";
151
152 status_or_int =
153 api.TIFFSetFieldU1(&tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
154 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
155 EXPECT_THAT(status_or_int.value(), IsTrue())
156 << "Can't set CompressionNone tag";
157
158 status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_IMAGEWIDTH, kWidth);
159 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
160 EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImageWidth tag";
161
162 status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_IMAGELENGTH, 1);
163 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
164 EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImageLenght tag";
165
166 status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_BITSPERSAMPLE, kBps);
167 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
168 EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set BitsPerSample tag";
169
170 status_or_int =
171 api.TIFFSetFieldU1(&tif, TIFFTAG_SAMPLESPERPIXEL, kSamplePerPixel);
172 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
173 EXPECT_THAT(status_or_int.value(), IsTrue())
174 << "Can't set SamplesPerPixel tag";
175
176 status_or_int =
177 api.TIFFSetFieldU1(&tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
178 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
179 EXPECT_THAT(status_or_int.value(), IsTrue())
180 << "Can't set PlanarConfiguration tag";
181
182 status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_ROWSPERSTRIP, kRowsPerStrip);
183 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
184 EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set RowsPerStrip tag";
185
186 status_or_int = api.TIFFDeferStrileArrayWriting(&tif);
187 ASSERT_THAT(status_or_int, IsOk())
188 << "TIFFDeferStrileArrayWriting fatal error";
189 EXPECT_THAT(status_or_int.value(), IsTrue())
190 << "TIFFDeferStrileArrayWriting return unexpected value";
191
192 status_or_int = api.TIFFWriteCheck(&tif, 0, test_var.PtrBefore());
193 ASSERT_THAT(status_or_int, IsOk()) << "TIFFWriteCheck fatal error";
194 EXPECT_THAT(status_or_int.value(), IsTrue())
195 << "TIFFWriteCheck return unexpected value";
196
197 status_or_int = api.TIFFWriteDirectory(&tif);
198 ASSERT_THAT(status_or_int, IsOk()) << "TIFFWriteDirectory fatal error";
199 EXPECT_THAT(status_or_int.value(), IsTrue())
200 << "TIFFWriteDirectory return unexpected value";
201
202 // Force writing of strile arrays
203 status_or_int = api.TIFFSetDirectory(&tif, 0);
204 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetDirectory fatal error";
205 EXPECT_THAT(status_or_int.value(), IsTrue())
206 << "TIFFSetDirectory return unexpected value";
207
208 status_or_int = api.TIFFForceStrileArrayWriting(&tif);
209 ASSERT_THAT(status_or_int, IsOk())
210 << "TIFFForceStrileArrayWriting fatal error";
211 EXPECT_THAT(status_or_int.value(), IsTrue())
212 << "TIFFForceStrileArrayWriting return unexpected value";
213
214 status_or_int = api.TIFFSetDirectory(&tif, 1);
215 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetDirectory fatal error";
216 EXPECT_THAT(status_or_int.value(), IsTrue())
217 << "TIFFSetDirectory return unexpected value";
218
219 status_or_int = api.TIFFForceStrileArrayWriting(&tif);
220 ASSERT_THAT(status_or_int, IsOk())
221 << "TIFFForceStrileArrayWriting fatal error";
222 EXPECT_THAT(status_or_int.value(), IsTrue())
223 << "TIFFForceStrileArrayWriting return unexpected value";
224
225 // Now write data on frist directory
226 status_or_int = api.TIFFSetDirectory(&tif, 0);
227 ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetDirectory fatal error";
228 EXPECT_THAT(status_or_int.value(), IsTrue())
229 << "TIFFSetDirectory return unexpected value";
230
231 if (tiled) {
232 for (int i = 0; i < (height + 15) / 16; ++i) {
233 std::array<uint8_t, kTileBufferSize> tilebuffer;
234 tilebuffer.fill(i);
235 sapi::v::Array<uint8_t> tilebuffer_(tilebuffer.data(), kTileBufferSize);
236
237 status_or_int = api.TIFFWriteEncodedTile(&tif, i, tilebuffer_.PtrBoth(),
238 kTileBufferSize);
239 ASSERT_THAT(status_or_int, IsOk()) << "TIFFWriteEncodedTile fatal error";
240 EXPECT_THAT(status_or_int.value(), Eq(kTileBufferSize))
241 << "line " << i << ": expected 256, got " << status_or_int.value();
242 }
243 } else {
244 for (int i = 0; i < height; ++i) {
245 sapi::v::UChar c(i);
246 status_or_long = api.TIFFWriteEncodedStrip(&tif, i, c.PtrBoth(), 1);
247 ASSERT_THAT(status_or_long, IsOk())
248 << "TIFFWriteEncodedStrip fatal error";
249 EXPECT_THAT(status_or_int.value(), Eq(1))
250 << "line " << i << ": expected 1, got " << status_or_int.value();
251
252 if (i == 1 && height > 100000) {
253 i = height - 2;
254 }
255 }
256 }
257
258 ASSERT_THAT(api.TIFFClose(&tif), IsOk()) << "TIFFClose fatal error";
259
260 sapi::v::ConstCStr r_var("r");
261 status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), r_var.PtrBefore());
262 ASSERT_THAT(status_or_tif, IsOk()) << "Could not open " << srcfile;
263
264 sapi::v::RemotePtr tif2(status_or_tif.value());
265 ASSERT_THAT(tif2.GetValue(), NotNull()) << "can't open " << srcfile;
266
267 if (tiled) {
268 for (int i = 0; i < (height + 15) / 16; ++i) {
269 for (int retry = 0; retry < 2; ++retry) {
270 std::array<uint8_t, kTileBufferSize> tilebuffer;
271 auto expected_c = static_cast<uint8_t>(i);
272 tilebuffer.fill(0);
273
274 sapi::v::Array<uint8_t> tilebuffer_(tilebuffer.data(), kTileBufferSize);
275 status_or_long = api.TIFFReadEncodedTile(
276 &tif2, i, tilebuffer_.PtrBoth(), kTileBufferSize);
277 ASSERT_THAT(status_or_long, IsOk())
278 << "TIFFReadEncodedTile fatal error";
279 EXPECT_THAT(status_or_long.value(), Eq(kTileBufferSize))
280 << "line " << i << ": expected 256, got " << status_or_long.value();
281
282 bool cmp = tilebuffer[0] != expected_c || tilebuffer[255] != expected_c;
283
284 EXPECT_THAT(tilebuffer[0], Eq(expected_c))
285 << "unexpected value at tile " << i << ": expected " << expected_c
286 << ", got " << tilebuffer[0];
287
288 EXPECT_THAT(tilebuffer[255], Eq(expected_c))
289 << "unexpected value at tile " << i << ": expected " << expected_c
290 << ", got " << tilebuffer[255];
291 if (cmp) {
292 ASSERT_THAT(api.TIFFClose(&tif2), IsOk()) << "TIFFClose fatal error";
293 }
294 }
295 }
296 } else {
297 for (int i = 0; i < height; ++i) {
298 for (int retry = 0; retry < 2; ++retry) {
299 sapi::v::UChar c(0);
300 auto expected_c = static_cast<uint8_t>(i);
301
302 status_or_long = api.TIFFReadEncodedStrip(&tif2, i, c.PtrBoth(), 1);
303 ASSERT_THAT(status_or_long, IsOk())
304 << "TIFFReadEncodedStrip fatal error";
305 EXPECT_THAT(status_or_long.value(), Eq(1))
306 << "line " << i << ": expected 1, got " << status_or_long.value();
307 EXPECT_THAT(c.GetValue(), Eq(expected_c))
308 << "unexpected value at line " << i << ": expected " << expected_c
309 << ", got " << c.GetValue();
310
311 if (c.GetValue() != expected_c) {
312 ASSERT_THAT(api.TIFFClose(&tif2), IsOk()) << "TIFFClose fatal error";
313 }
314 }
315 }
316 }
317
318 ASSERT_THAT(api.TIFFClose(&tif2), IsOk()) << "TIFFClose fatal error";
319
320 unlink(srcfile.c_str());
321 }
322
TEST(SandboxTest,DeferStrileWriting)323 TEST(SandboxTest, DeferStrileWriting) {
324 for (int tiled = 0; tiled <= 1; ++tiled) {
325 TestWriting("w", tiled, 1);
326 TestWriting("w", tiled, 10);
327 TestWriting("w8", tiled, 1);
328 TestWriting("wD", tiled, 1);
329 }
330 }
331
332 } // namespace
333