Home | History | Annotate | Download | only in component
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdio.h>
     18 
     19 #include <string>
     20 #include <vector>
     21 
     22 #include <android-base/file.h>
     23 #include <android-base/memory.h>
     24 #include <android-base/test_utils.h>
     25 #include <applypatch/imgdiff.h>
     26 #include <applypatch/imgpatch.h>
     27 #include <gtest/gtest.h>
     28 #include <ziparchive/zip_writer.h>
     29 
     30 using android::base::get_unaligned;
     31 
     32 // Sanity check for the given imgdiff patch header.
     33 static void verify_patch_header(const std::string& patch, size_t* num_normal, size_t* num_raw,
     34                                 size_t* num_deflate) {
     35   const size_t size = patch.size();
     36   const char* data = patch.data();
     37 
     38   ASSERT_GE(size, 12U);
     39   ASSERT_EQ("IMGDIFF2", std::string(data, 8));
     40 
     41   const int num_chunks = get_unaligned<int32_t>(data + 8);
     42   ASSERT_GE(num_chunks, 0);
     43 
     44   size_t normal = 0;
     45   size_t raw = 0;
     46   size_t deflate = 0;
     47 
     48   size_t pos = 12;
     49   for (int i = 0; i < num_chunks; ++i) {
     50     ASSERT_LE(pos + 4, size);
     51     int type = get_unaligned<int32_t>(data + pos);
     52     pos += 4;
     53     if (type == CHUNK_NORMAL) {
     54       pos += 24;
     55       ASSERT_LE(pos, size);
     56       normal++;
     57     } else if (type == CHUNK_RAW) {
     58       ASSERT_LE(pos + 4, size);
     59       ssize_t data_len = get_unaligned<int32_t>(data + pos);
     60       ASSERT_GT(data_len, 0);
     61       pos += 4 + data_len;
     62       ASSERT_LE(pos, size);
     63       raw++;
     64     } else if (type == CHUNK_DEFLATE) {
     65       pos += 60;
     66       ASSERT_LE(pos, size);
     67       deflate++;
     68     } else {
     69       FAIL() << "Invalid patch type: " << type;
     70     }
     71   }
     72 
     73   if (num_normal != nullptr) *num_normal = normal;
     74   if (num_raw != nullptr) *num_raw = raw;
     75   if (num_deflate != nullptr) *num_deflate = deflate;
     76 }
     77 
     78 static void verify_patched_image(const std::string& src, const std::string& patch,
     79                                  const std::string& tgt) {
     80   std::string patched;
     81   ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
     82                                reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
     83                                [&patched](const unsigned char* data, size_t len) {
     84                                  patched.append(reinterpret_cast<const char*>(data), len);
     85                                  return len;
     86                                }));
     87   ASSERT_EQ(tgt, patched);
     88 }
     89 
     90 TEST(ImgdiffTest, invalid_args) {
     91   // Insufficient inputs.
     92   ASSERT_EQ(2, imgdiff(1, (const char* []){ "imgdiff" }));
     93   ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-z" }));
     94   ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-b" }));
     95   ASSERT_EQ(2, imgdiff(3, (const char* []){ "imgdiff", "-z", "-b" }));
     96 
     97   // Failed to read bonus file.
     98   ASSERT_EQ(1, imgdiff(3, (const char* []){ "imgdiff", "-b", "doesntexist" }));
     99 
    100   // Failed to read input files.
    101   ASSERT_EQ(1, imgdiff(4, (const char* []){ "imgdiff", "doesntexist", "doesntexist", "output" }));
    102   ASSERT_EQ(
    103       1, imgdiff(5, (const char* []){ "imgdiff", "-z", "doesntexist", "doesntexist", "output" }));
    104 }
    105 
    106 TEST(ImgdiffTest, image_mode_smoke) {
    107   // Random bytes.
    108   const std::string src("abcdefg");
    109   TemporaryFile src_file;
    110   ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
    111 
    112   const std::string tgt("abcdefgxyz");
    113   TemporaryFile tgt_file;
    114   ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
    115 
    116   TemporaryFile patch_file;
    117   std::vector<const char*> args = {
    118     "imgdiff", src_file.path, tgt_file.path, patch_file.path,
    119   };
    120   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    121 
    122   // Verify.
    123   std::string patch;
    124   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    125 
    126   // Expect one CHUNK_RAW entry.
    127   size_t num_normal;
    128   size_t num_raw;
    129   size_t num_deflate;
    130   verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
    131   ASSERT_EQ(0U, num_normal);
    132   ASSERT_EQ(0U, num_deflate);
    133   ASSERT_EQ(1U, num_raw);
    134 
    135   verify_patched_image(src, patch, tgt);
    136 }
    137 
    138 TEST(ImgdiffTest, zip_mode_smoke_store) {
    139   // Construct src and tgt zip files.
    140   TemporaryFile src_file;
    141   FILE* src_file_ptr = fdopen(src_file.fd, "wb");
    142   ZipWriter src_writer(src_file_ptr);
    143   ASSERT_EQ(0, src_writer.StartEntry("file1.txt", 0));  // Store mode.
    144   const std::string src_content("abcdefg");
    145   ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
    146   ASSERT_EQ(0, src_writer.FinishEntry());
    147   ASSERT_EQ(0, src_writer.Finish());
    148   ASSERT_EQ(0, fclose(src_file_ptr));
    149 
    150   TemporaryFile tgt_file;
    151   FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
    152   ZipWriter tgt_writer(tgt_file_ptr);
    153   ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", 0));  // Store mode.
    154   const std::string tgt_content("abcdefgxyz");
    155   ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
    156   ASSERT_EQ(0, tgt_writer.FinishEntry());
    157   ASSERT_EQ(0, tgt_writer.Finish());
    158   ASSERT_EQ(0, fclose(tgt_file_ptr));
    159 
    160   // Compute patch.
    161   TemporaryFile patch_file;
    162   std::vector<const char*> args = {
    163     "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
    164   };
    165   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    166 
    167   // Verify.
    168   std::string tgt;
    169   ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
    170   std::string src;
    171   ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
    172   std::string patch;
    173   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    174 
    175   // Expect one CHUNK_RAW entry.
    176   size_t num_normal;
    177   size_t num_raw;
    178   size_t num_deflate;
    179   verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
    180   ASSERT_EQ(0U, num_normal);
    181   ASSERT_EQ(0U, num_deflate);
    182   ASSERT_EQ(1U, num_raw);
    183 
    184   verify_patched_image(src, patch, tgt);
    185 }
    186 
    187 TEST(ImgdiffTest, zip_mode_smoke_compressed) {
    188   // Construct src and tgt zip files.
    189   TemporaryFile src_file;
    190   FILE* src_file_ptr = fdopen(src_file.fd, "wb");
    191   ZipWriter src_writer(src_file_ptr);
    192   ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
    193   const std::string src_content("abcdefg");
    194   ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
    195   ASSERT_EQ(0, src_writer.FinishEntry());
    196   ASSERT_EQ(0, src_writer.Finish());
    197   ASSERT_EQ(0, fclose(src_file_ptr));
    198 
    199   TemporaryFile tgt_file;
    200   FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
    201   ZipWriter tgt_writer(tgt_file_ptr);
    202   ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
    203   const std::string tgt_content("abcdefgxyz");
    204   ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
    205   ASSERT_EQ(0, tgt_writer.FinishEntry());
    206   ASSERT_EQ(0, tgt_writer.Finish());
    207   ASSERT_EQ(0, fclose(tgt_file_ptr));
    208 
    209   // Compute patch.
    210   TemporaryFile patch_file;
    211   std::vector<const char*> args = {
    212     "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
    213   };
    214   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    215 
    216   // Verify.
    217   std::string tgt;
    218   ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
    219   std::string src;
    220   ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
    221   std::string patch;
    222   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    223 
    224   // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
    225   size_t num_normal;
    226   size_t num_raw;
    227   size_t num_deflate;
    228   verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
    229   ASSERT_EQ(0U, num_normal);
    230   ASSERT_EQ(1U, num_deflate);
    231   ASSERT_EQ(2U, num_raw);
    232 
    233   verify_patched_image(src, patch, tgt);
    234 }
    235 
    236 TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) {
    237   // Construct src and tgt zip files.
    238   TemporaryFile src_file;
    239   FILE* src_file_ptr = fdopen(src_file.fd, "wb");
    240   ZipWriter src_writer(src_file_ptr);
    241   ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
    242   const std::string src_content("abcdefg");
    243   ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
    244   ASSERT_EQ(0, src_writer.FinishEntry());
    245   ASSERT_EQ(0, src_writer.Finish());
    246   ASSERT_EQ(0, fclose(src_file_ptr));
    247 
    248   TemporaryFile tgt_file;
    249   FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
    250   ZipWriter tgt_writer(tgt_file_ptr);
    251   ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
    252   const std::string tgt_content("abcdefgxyz");
    253   ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
    254   ASSERT_EQ(0, tgt_writer.FinishEntry());
    255   ASSERT_EQ(0, tgt_writer.Finish());
    256   // Add trailing zeros to the target zip file.
    257   std::vector<uint8_t> zeros(10);
    258   ASSERT_EQ(zeros.size(), fwrite(zeros.data(), sizeof(uint8_t), zeros.size(), tgt_file_ptr));
    259   ASSERT_EQ(0, fclose(tgt_file_ptr));
    260 
    261   // Compute patch.
    262   TemporaryFile patch_file;
    263   std::vector<const char*> args = {
    264     "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
    265   };
    266   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    267 
    268   // Verify.
    269   std::string tgt;
    270   ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
    271   std::string src;
    272   ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
    273   std::string patch;
    274   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    275 
    276   // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
    277   size_t num_normal;
    278   size_t num_raw;
    279   size_t num_deflate;
    280   verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
    281   ASSERT_EQ(0U, num_normal);
    282   ASSERT_EQ(1U, num_deflate);
    283   ASSERT_EQ(2U, num_raw);
    284 
    285   verify_patched_image(src, patch, tgt);
    286 }
    287 
    288 TEST(ImgdiffTest, image_mode_simple) {
    289   // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
    290   const std::vector<char> src_data = { 'a',    'b',    'c',    'd',    'e',    'f',    'g',
    291                                        'h',    '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
    292                                        '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
    293                                        '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
    294                                        '\x00', '\x00', '\x00' };
    295   const std::string src(src_data.cbegin(), src_data.cend());
    296   TemporaryFile src_file;
    297   ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
    298 
    299   // tgt: "abcdefgxyz" + gzipped "xxyyzz".
    300   const std::vector<char> tgt_data = {
    301     'a',    'b',    'c',    'd',    'e',    'f',    'g',    'x',    'y',    'z',    '\x1f', '\x8b',
    302     '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
    303     '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
    304   };
    305   const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
    306   TemporaryFile tgt_file;
    307   ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
    308 
    309   TemporaryFile patch_file;
    310   std::vector<const char*> args = {
    311     "imgdiff", src_file.path, tgt_file.path, patch_file.path,
    312   };
    313   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    314 
    315   // Verify.
    316   std::string patch;
    317   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    318 
    319   // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
    320   size_t num_normal;
    321   size_t num_raw;
    322   size_t num_deflate;
    323   verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
    324   ASSERT_EQ(0U, num_normal);
    325   ASSERT_EQ(1U, num_deflate);
    326   ASSERT_EQ(2U, num_raw);
    327 
    328   verify_patched_image(src, patch, tgt);
    329 }
    330 
    331 TEST(ImgdiffTest, image_mode_bad_gzip) {
    332   // Modify the uncompressed length in the gzip footer.
    333   const std::vector<char> src_data = { 'a',    'b',    'c',    'd',    'e',    'f',    'g',
    334                                        'h',    '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
    335                                        '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
    336                                        '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
    337                                        '\xff', '\xff', '\xff' };
    338   const std::string src(src_data.cbegin(), src_data.cend());
    339   TemporaryFile src_file;
    340   ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
    341 
    342   // Modify the uncompressed length in the gzip footer.
    343   const std::vector<char> tgt_data = {
    344     'a',    'b',    'c',    'd',    'e',    'f',    'g',    'x',    'y',    'z',    '\x1f', '\x8b',
    345     '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
    346     '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\xff', '\xff', '\xff'
    347   };
    348   const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
    349   TemporaryFile tgt_file;
    350   ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
    351 
    352   TemporaryFile patch_file;
    353   std::vector<const char*> args = {
    354     "imgdiff", src_file.path, tgt_file.path, patch_file.path,
    355   };
    356   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    357 
    358   // Verify.
    359   std::string patch;
    360   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    361   verify_patched_image(src, patch, tgt);
    362 }
    363 
    364 TEST(ImgdiffTest, image_mode_different_num_chunks) {
    365   // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd) + gzipped "test".
    366   const std::vector<char> src_data = {
    367     'a',    'b',    'c',    'd',    'e',    'f',    'g',    'h',    '\x1f', '\x8b', '\x08',
    368     '\x00', '\xc4', '\x1e', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', '\x02',
    369     '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', '\x00', '\x00', '\x00', '\x1f', '\x8b',
    370     '\x08', '\x00', '\xb2', '\x3a', '\x53', '\x58', '\x00', '\x03', '\x2b', '\x49', '\x2d',
    371     '\x2e', '\x01', '\x00', '\x0c', '\x7e', '\x7f', '\xd8', '\x04', '\x00', '\x00', '\x00'
    372   };
    373   const std::string src(src_data.cbegin(), src_data.cend());
    374   TemporaryFile src_file;
    375   ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
    376 
    377   // tgt: "abcdefgxyz" + gzipped "xxyyzz".
    378   const std::vector<char> tgt_data = {
    379     'a',    'b',    'c',    'd',    'e',    'f',    'g',    'x',    'y',    'z',    '\x1f', '\x8b',
    380     '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
    381     '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
    382   };
    383   const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
    384   TemporaryFile tgt_file;
    385   ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
    386 
    387   TemporaryFile patch_file;
    388   std::vector<const char*> args = {
    389     "imgdiff", src_file.path, tgt_file.path, patch_file.path,
    390   };
    391   ASSERT_EQ(1, imgdiff(args.size(), args.data()));
    392 }
    393 
    394 TEST(ImgdiffTest, image_mode_merge_chunks) {
    395   // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
    396   const std::vector<char> src_data = { 'a',    'b',    'c',    'd',    'e',    'f',    'g',
    397                                        'h',    '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
    398                                        '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
    399                                        '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
    400                                        '\x00', '\x00', '\x00' };
    401   const std::string src(src_data.cbegin(), src_data.cend());
    402   TemporaryFile src_file;
    403   ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
    404 
    405   // tgt: gzipped "xyz" + "abcdefgh".
    406   const std::vector<char> tgt_data = {
    407     '\x1f', '\x8b', '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8',
    408     '\xa8', '\xac', '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00',
    409     '\x00', '\x00', 'a',    'b',    'c',    'd',    'e',    'f',    'g',    'x',    'y',    'z'
    410   };
    411   const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
    412   TemporaryFile tgt_file;
    413   ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
    414 
    415   // Since a gzipped entry will become CHUNK_RAW (header) + CHUNK_DEFLATE (data) +
    416   // CHUNK_RAW (footer), they both should contain the same chunk types after merging.
    417 
    418   TemporaryFile patch_file;
    419   std::vector<const char*> args = {
    420     "imgdiff", src_file.path, tgt_file.path, patch_file.path,
    421   };
    422   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    423 
    424   // Verify.
    425   std::string patch;
    426   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    427 
    428   // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
    429   size_t num_normal;
    430   size_t num_raw;
    431   size_t num_deflate;
    432   verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
    433   ASSERT_EQ(0U, num_normal);
    434   ASSERT_EQ(1U, num_deflate);
    435   ASSERT_EQ(2U, num_raw);
    436 
    437   verify_patched_image(src, patch, tgt);
    438 }
    439 
    440 TEST(ImgdiffTest, image_mode_spurious_magic) {
    441   // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
    442   const std::vector<char> src_data = { 'a',    'b',    'c',    'd',    'e',    'f',    'g',
    443                                        'h',    '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
    444                                        '\x53', '\x58', 't',    'e',    's',    't' };
    445   const std::string src(src_data.cbegin(), src_data.cend());
    446   TemporaryFile src_file;
    447   ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
    448 
    449   // tgt: "abcdefgxyz".
    450   const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
    451   const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
    452   TemporaryFile tgt_file;
    453   ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
    454 
    455   TemporaryFile patch_file;
    456   std::vector<const char*> args = {
    457     "imgdiff", src_file.path, tgt_file.path, patch_file.path,
    458   };
    459   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    460 
    461   // Verify.
    462   std::string patch;
    463   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    464 
    465   // Expect one CHUNK_RAW (header) entry.
    466   size_t num_normal;
    467   size_t num_raw;
    468   size_t num_deflate;
    469   verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
    470   ASSERT_EQ(0U, num_normal);
    471   ASSERT_EQ(0U, num_deflate);
    472   ASSERT_EQ(1U, num_raw);
    473 
    474   verify_patched_image(src, patch, tgt);
    475 }
    476 
    477 TEST(ImgdiffTest, image_mode_short_input1) {
    478   // src: "abcdefgh" + '0x1f8b0b'.
    479   const std::vector<char> src_data = { 'a', 'b', 'c',    'd',    'e',   'f',
    480                                        'g', 'h', '\x1f', '\x8b', '\x08' };
    481   const std::string src(src_data.cbegin(), src_data.cend());
    482   TemporaryFile src_file;
    483   ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
    484 
    485   // tgt: "abcdefgxyz".
    486   const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
    487   const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
    488   TemporaryFile tgt_file;
    489   ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
    490 
    491   TemporaryFile patch_file;
    492   std::vector<const char*> args = {
    493     "imgdiff", src_file.path, tgt_file.path, patch_file.path,
    494   };
    495   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    496 
    497   // Verify.
    498   std::string patch;
    499   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    500 
    501   // Expect one CHUNK_RAW (header) entry.
    502   size_t num_normal;
    503   size_t num_raw;
    504   size_t num_deflate;
    505   verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
    506   ASSERT_EQ(0U, num_normal);
    507   ASSERT_EQ(0U, num_deflate);
    508   ASSERT_EQ(1U, num_raw);
    509 
    510   verify_patched_image(src, patch, tgt);
    511 }
    512 
    513 TEST(ImgdiffTest, image_mode_short_input2) {
    514   // src: "abcdefgh" + '0x1f8b0b00'.
    515   const std::vector<char> src_data = { 'a', 'b', 'c',    'd',    'e',    'f',
    516                                        'g', 'h', '\x1f', '\x8b', '\x08', '\x00' };
    517   const std::string src(src_data.cbegin(), src_data.cend());
    518   TemporaryFile src_file;
    519   ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
    520 
    521   // tgt: "abcdefgxyz".
    522   const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
    523   const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
    524   TemporaryFile tgt_file;
    525   ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
    526 
    527   TemporaryFile patch_file;
    528   std::vector<const char*> args = {
    529     "imgdiff", src_file.path, tgt_file.path, patch_file.path,
    530   };
    531   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    532 
    533   // Verify.
    534   std::string patch;
    535   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    536 
    537   // Expect one CHUNK_RAW (header) entry.
    538   size_t num_normal;
    539   size_t num_raw;
    540   size_t num_deflate;
    541   verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
    542   ASSERT_EQ(0U, num_normal);
    543   ASSERT_EQ(0U, num_deflate);
    544   ASSERT_EQ(1U, num_raw);
    545 
    546   verify_patched_image(src, patch, tgt);
    547 }
    548 
    549 TEST(ImgdiffTest, image_mode_single_entry_long) {
    550   // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
    551   const std::vector<char> src_data = { 'a',    'b',    'c',    'd',    'e',    'f',    'g',
    552                                        'h',    '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
    553                                        '\x53', '\x58', 't',    'e',    's',    't' };
    554   const std::string src(src_data.cbegin(), src_data.cend());
    555   TemporaryFile src_file;
    556   ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
    557 
    558   // tgt: "abcdefgxyz" + 200 bytes.
    559   std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
    560   tgt_data.resize(tgt_data.size() + 200);
    561 
    562   const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
    563   TemporaryFile tgt_file;
    564   ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
    565 
    566   TemporaryFile patch_file;
    567   std::vector<const char*> args = {
    568     "imgdiff", src_file.path, tgt_file.path, patch_file.path,
    569   };
    570   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    571 
    572   // Verify.
    573   std::string patch;
    574   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    575 
    576   // Expect one CHUNK_NORMAL entry, since it's exceeding the 160-byte limit for RAW.
    577   size_t num_normal;
    578   size_t num_raw;
    579   size_t num_deflate;
    580   verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
    581   ASSERT_EQ(1U, num_normal);
    582   ASSERT_EQ(0U, num_deflate);
    583   ASSERT_EQ(0U, num_raw);
    584 
    585   verify_patched_image(src, patch, tgt);
    586 }
    587 
    588 TEST(ImgpatchTest, image_mode_patch_corruption) {
    589   // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
    590   const std::vector<char> src_data = { 'a',    'b',    'c',    'd',    'e',    'f',    'g',
    591                                        'h',    '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
    592                                        '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
    593                                        '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
    594                                        '\x00', '\x00', '\x00' };
    595   const std::string src(src_data.cbegin(), src_data.cend());
    596   TemporaryFile src_file;
    597   ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
    598 
    599   // tgt: "abcdefgxyz" + gzipped "xxyyzz".
    600   const std::vector<char> tgt_data = {
    601     'a',    'b',    'c',    'd',    'e',    'f',    'g',    'x',    'y',    'z',    '\x1f', '\x8b',
    602     '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
    603     '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
    604   };
    605   const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
    606   TemporaryFile tgt_file;
    607   ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
    608 
    609   TemporaryFile patch_file;
    610   std::vector<const char*> args = {
    611     "imgdiff", src_file.path, tgt_file.path, patch_file.path,
    612   };
    613   ASSERT_EQ(0, imgdiff(args.size(), args.data()));
    614 
    615   // Verify.
    616   std::string patch;
    617   ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
    618   verify_patched_image(src, patch, tgt);
    619 
    620   // Corrupt the end of the patch and expect the ApplyImagePatch to fail.
    621   patch.insert(patch.end() - 10, 10, '0');
    622   ASSERT_EQ(-1, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
    623                                 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
    624                                 [](const unsigned char* /*data*/, size_t len) { return len; }));
    625 }
    626