| OLD | NEW |
| 1 // Copyright 2003, 2004 Colin Percival | 1 // Copyright 2003, 2004 Colin Percival |
| 2 // All rights reserved | 2 // All rights reserved |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted providing that the following conditions | 5 // modification, are permitted providing that the following conditions |
| 6 // are met: | 6 // are met: |
| 7 // 1. Redistributions of source code must retain the above copyright | 7 // 1. Redistributions of source code must retain the above copyright |
| 8 // notice, this list of conditions and the following disclaimer. | 8 // notice, this list of conditions and the following disclaimer. |
| 9 // 2. Redistributions in binary form must reproduce the above copyright | 9 // 2. Redistributions in binary form must reproduce the above copyright |
| 10 // notice, this list of conditions and the following disclaimer in the | 10 // notice, this list of conditions and the following disclaimer in the |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 // --Rahul Kuchhal | 36 // --Rahul Kuchhal |
| 37 // 2009-03-31 - Change to use Streams. Added lots of comments. | 37 // 2009-03-31 - Change to use Streams. Added lots of comments. |
| 38 // --Stephen Adams <sra@chromium.org> | 38 // --Stephen Adams <sra@chromium.org> |
| 39 // 2010-05-26 - Use a paged array for V and I. The address space may be too | 39 // 2010-05-26 - Use a paged array for V and I. The address space may be too |
| 40 // fragmented for these big arrays to be contiguous. | 40 // fragmented for these big arrays to be contiguous. |
| 41 // --Stephen Adams <sra@chromium.org> | 41 // --Stephen Adams <sra@chromium.org> |
| 42 // 2015-08-03 - Extract qsufsort portion to a separate file. | 42 // 2015-08-03 - Extract qsufsort portion to a separate file. |
| 43 // --Samuel Huang <huangs@chromium.org> | 43 // --Samuel Huang <huangs@chromium.org> |
| 44 // 2015-08-12 - Interface change to search(). | 44 // 2015-08-12 - Interface change to search(). |
| 45 // --Samuel Huang <huangs@chromium.org> | 45 // --Samuel Huang <huangs@chromium.org> |
| 46 // 2016-07-14 - Replacing qsufsort with divsufsort. |
| 47 // --Samuel Huang <huangs@chromium.org> |
| 48 |
| 46 | 49 |
| 47 // Copyright 2016 The Chromium Authors. All rights reserved. | 50 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 48 // Use of this source code is governed by a BSD-style license that can be | 51 // Use of this source code is governed by a BSD-style license that can be |
| 49 // found in the LICENSE file. | 52 // found in the LICENSE file. |
| 50 | 53 |
| 51 #include "courgette/third_party/bsdiff/bsdiff.h" | 54 #include "courgette/third_party/bsdiff/bsdiff.h" |
| 52 | 55 |
| 53 #include <stddef.h> | 56 #include <stddef.h> |
| 54 #include <stdint.h> | 57 #include <stdint.h> |
| 55 #include <stdlib.h> | 58 #include <stdlib.h> |
| 59 |
| 56 #include <algorithm> | 60 #include <algorithm> |
| 57 | 61 |
| 58 #include "base/logging.h" | 62 #include "base/logging.h" |
| 59 #include "base/strings/string_util.h" | 63 #include "base/strings/string_util.h" |
| 60 #include "base/time/time.h" | 64 #include "base/time/time.h" |
| 61 | 65 |
| 62 #include "courgette/crc.h" | 66 #include "courgette/crc.h" |
| 63 #include "courgette/streams.h" | 67 #include "courgette/streams.h" |
| 64 #include "courgette/third_party/bsdiff/bsdiff_search.h" | 68 #include "courgette/third_party/bsdiff/bsdiff_search.h" |
| 65 #include "courgette/third_party/bsdiff/paged_array.h" | 69 #include "courgette/third_party/bsdiff/paged_array.h" |
| 66 #include "courgette/third_party/bsdiff/qsufsort.h" | 70 #include "courgette/third_party/divsufsort/divsufsort.h" |
| 67 | 71 |
| 68 namespace courgette { | 72 namespace courgette { |
| 69 | 73 |
| 70 static CheckBool WriteHeader(SinkStream* stream, MBSPatchHeader* header) { | 74 static CheckBool WriteHeader(SinkStream* stream, MBSPatchHeader* header) { |
| 71 bool ok = stream->Write(header->tag, sizeof(header->tag)); | 75 bool ok = stream->Write(header->tag, sizeof(header->tag)); |
| 72 ok &= stream->WriteVarint32(header->slen); | 76 ok &= stream->WriteVarint32(header->slen); |
| 73 ok &= stream->WriteVarint32(header->scrc32); | 77 ok &= stream->WriteVarint32(header->scrc32); |
| 74 ok &= stream->WriteVarint32(header->dlen); | 78 ok &= stream->WriteVarint32(header->dlen); |
| 75 return ok; | 79 return ok; |
| 76 } | 80 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 88 SinkStream* control_stream_seeks = patch_streams.stream(2); | 92 SinkStream* control_stream_seeks = patch_streams.stream(2); |
| 89 SinkStream* diff_skips = patch_streams.stream(3); | 93 SinkStream* diff_skips = patch_streams.stream(3); |
| 90 SinkStream* diff_bytes = patch_streams.stream(4); | 94 SinkStream* diff_bytes = patch_streams.stream(4); |
| 91 SinkStream* extra_bytes = patch_streams.stream(5); | 95 SinkStream* extra_bytes = patch_streams.stream(5); |
| 92 | 96 |
| 93 const uint8_t* old = old_stream->Buffer(); | 97 const uint8_t* old = old_stream->Buffer(); |
| 94 const int oldsize = static_cast<int>(old_stream->Remaining()); | 98 const int oldsize = static_cast<int>(old_stream->Remaining()); |
| 95 | 99 |
| 96 uint32_t pending_diff_zeros = 0; | 100 uint32_t pending_diff_zeros = 0; |
| 97 | 101 |
| 98 PagedArray<int> I; | 102 PagedArray<divsuf::saidx_t> I; |
| 99 PagedArray<int> V; | |
| 100 | 103 |
| 101 if (!I.Allocate(oldsize + 1)) { | 104 if (!I.Allocate(oldsize + 1)) { |
| 102 LOG(ERROR) << "Could not allocate I[], " << ((oldsize + 1) * sizeof(int)) | 105 LOG(ERROR) << "Could not allocate I[], " << ((oldsize + 1) * sizeof(int)) |
| 103 << " bytes"; | 106 << " bytes"; |
| 104 return MEM_ERROR; | 107 return MEM_ERROR; |
| 105 } | 108 } |
| 106 | 109 |
| 107 if (!V.Allocate(oldsize + 1)) { | |
| 108 LOG(ERROR) << "Could not allocate V[], " << ((oldsize + 1) * sizeof(int)) | |
| 109 << " bytes"; | |
| 110 return MEM_ERROR; | |
| 111 } | |
| 112 | |
| 113 base::Time q_start_time = base::Time::Now(); | 110 base::Time q_start_time = base::Time::Now(); |
| 114 qsuf::qsufsort<PagedArray<int>&>(I, V, old, oldsize); | 111 |
| 115 VLOG(1) << " done qsufsort " | 112 // Divsufsort excludes the empty-string suffix, so add it manually. |
| 116 << (base::Time::Now() - q_start_time).InSecondsF(); | 113 I[0] = oldsize; |
| 117 V.clear(); | 114 divsuf::saint_t result = divsuf::divsufsort(old, I.begin() + 1, oldsize); |
| 115 if (result != 0) |
| 116 return UNEXPECTED_ERROR; |
| 118 | 117 |
| 119 const uint8_t* newbuf = new_stream->Buffer(); | 118 const uint8_t* newbuf = new_stream->Buffer(); |
| 120 const int newsize = static_cast<int>(new_stream->Remaining()); | 119 const int newsize = static_cast<int>(new_stream->Remaining()); |
| 121 | 120 |
| 122 int control_length = 0; | 121 int control_length = 0; |
| 123 int diff_bytes_length = 0; | 122 int diff_bytes_length = 0; |
| 124 int diff_bytes_nonzero = 0; | 123 int diff_bytes_nonzero = 0; |
| 125 int extra_bytes_length = 0; | 124 int extra_bytes_length = 0; |
| 126 | 125 |
| 127 // The patch format is a sequence of triples <copy,extra,seek> where 'copy' is | 126 // The patch format is a sequence of triples <copy,extra,seek> where 'copy' is |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 int scan = 0; | 166 int scan = 0; |
| 168 int match_length = 0; | 167 int match_length = 0; |
| 169 | 168 |
| 170 while (scan < newsize) { | 169 while (scan < newsize) { |
| 171 int pos = 0; | 170 int pos = 0; |
| 172 int oldscore = 0; // Count of how many bytes of the current match at |scan| | 171 int oldscore = 0; // Count of how many bytes of the current match at |scan| |
| 173 // extend the match at |lastscan|. | 172 // extend the match at |lastscan|. |
| 174 | 173 |
| 175 scan += match_length; | 174 scan += match_length; |
| 176 for (int scsc = scan; scan < newsize; ++scan) { | 175 for (int scsc = scan; scan < newsize; ++scan) { |
| 177 match_length = courgette::search<PagedArray<int>&>( | 176 match_length = bsdiff::search<PagedArray<divsuf::saidx_t>&>( |
| 178 I, old, oldsize, newbuf + scan, newsize - scan, &pos); | 177 I, old, oldsize, newbuf + scan, newsize - scan, &pos); |
| 179 | |
| 180 for (; scsc < scan + match_length; scsc++) | 178 for (; scsc < scan + match_length; scsc++) |
| 181 if ((scsc + lastoffset < oldsize) && | 179 if ((scsc + lastoffset < oldsize) && |
| 182 (old[scsc + lastoffset] == newbuf[scsc])) | 180 (old[scsc + lastoffset] == newbuf[scsc])) |
| 183 oldscore++; | 181 oldscore++; |
| 184 | 182 |
| 185 if ((match_length == oldscore) && (match_length != 0)) | 183 if ((match_length == oldscore) && (match_length != 0)) |
| 186 break; // Good continuing match, case (1) | 184 break; // Good continuing match, case (1) |
| 187 if (match_length > oldscore + 8) | 185 if (match_length > oldscore + 8) |
| 188 break; // New seed match, case (2) | 186 break; // New seed match, case (2) |
| 189 | 187 |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 << " extra bytes: " << extra_bytes_length | 331 << " extra bytes: " << extra_bytes_length |
| 334 << "\nUncompressed bsdiff patch size " | 332 << "\nUncompressed bsdiff patch size " |
| 335 << patch_stream->Length() - initial_patch_stream_length | 333 << patch_stream->Length() - initial_patch_stream_length |
| 336 << "\nEnd bsdiff " | 334 << "\nEnd bsdiff " |
| 337 << (base::Time::Now() - start_bsdiff_time).InSecondsF(); | 335 << (base::Time::Now() - start_bsdiff_time).InSecondsF(); |
| 338 | 336 |
| 339 return OK; | 337 return OK; |
| 340 } | 338 } |
| 341 | 339 |
| 342 } // namespace courgette | 340 } // namespace courgette |
| OLD | NEW |