| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <vector> | 5 #include <vector> |
| 6 #include <string> | 6 #include <string> |
| 7 | 7 |
| 8 #include "base/at_exit.h" | 8 #include "base/at_exit.h" |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 | 39 |
| 40 void Problem(const char* format, ...) { | 40 void Problem(const char* format, ...) { |
| 41 va_list args; | 41 va_list args; |
| 42 va_start(args, format); | 42 va_start(args, format); |
| 43 vfprintf(stderr, format, args); | 43 vfprintf(stderr, format, args); |
| 44 fprintf(stderr, "\n"); | 44 fprintf(stderr, "\n"); |
| 45 va_end(args); | 45 va_end(args); |
| 46 exit(1); | 46 exit(1); |
| 47 } | 47 } |
| 48 | 48 |
| 49 std::string ReadOrFail(const std::wstring& file_name, const char* kind) { | 49 std::string ReadOrFail(const FilePath& file_name, const char* kind) { |
| 50 #if defined(OS_WIN) | |
| 51 FilePath file_path(file_name); | |
| 52 #else | |
| 53 FilePath file_path(WideToASCII(file_name)); | |
| 54 #endif | |
| 55 int64 file_size = 0; | 50 int64 file_size = 0; |
| 56 if (!file_util::GetFileSize(file_path, &file_size)) | 51 if (!file_util::GetFileSize(file_name, &file_size)) |
| 57 Problem("Can't read %s file.", kind); | 52 Problem("Can't read %s file.", kind); |
| 58 std::string buffer; | 53 std::string buffer; |
| 59 buffer.reserve(static_cast<size_t>(file_size)); | 54 buffer.reserve(static_cast<size_t>(file_size)); |
| 60 if (!file_util::ReadFileToString(file_path, &buffer)) | 55 if (!file_util::ReadFileToString(file_name, &buffer)) |
| 61 Problem("Can't read %s file.", kind); | 56 Problem("Can't read %s file.", kind); |
| 62 return buffer; | 57 return buffer; |
| 63 } | 58 } |
| 64 | 59 |
| 65 void WriteSinkToFile(const courgette::SinkStream *sink, | 60 void WriteSinkToFile(const courgette::SinkStream *sink, |
| 66 const std::wstring& output_file) { | 61 const FilePath& output_file) { |
| 67 #if defined(OS_WIN) | |
| 68 FilePath output_path(output_file); | |
| 69 #else | |
| 70 FilePath output_path(WideToASCII(output_file)); | |
| 71 #endif | |
| 72 int count = | 62 int count = |
| 73 file_util::WriteFile(output_path, | 63 file_util::WriteFile(output_file, |
| 74 reinterpret_cast<const char*>(sink->Buffer()), | 64 reinterpret_cast<const char*>(sink->Buffer()), |
| 75 static_cast<int>(sink->Length())); | 65 static_cast<int>(sink->Length())); |
| 76 if (count == -1) | 66 if (count == -1) |
| 77 Problem("Can't write output."); | 67 Problem("Can't write output."); |
| 78 if (static_cast<size_t>(count) != sink->Length()) | 68 if (static_cast<size_t>(count) != sink->Length()) |
| 79 Problem("Incomplete write."); | 69 Problem("Incomplete write."); |
| 80 } | 70 } |
| 81 | 71 |
| 82 void Disassemble(const std::wstring& input_file, | 72 void Disassemble(const FilePath& input_file, |
| 83 const std::wstring& output_file) { | 73 const FilePath& output_file) { |
| 84 std::string buffer = ReadOrFail(input_file, "input"); | 74 std::string buffer = ReadOrFail(input_file, "input"); |
| 85 | 75 |
| 86 courgette::AssemblyProgram* program = NULL; | 76 courgette::AssemblyProgram* program = NULL; |
| 87 const courgette::Status parse_status = | 77 const courgette::Status parse_status = |
| 88 courgette::ParseDetectedExecutable(buffer.c_str(), buffer.length(), | 78 courgette::ParseDetectedExecutable(buffer.c_str(), buffer.length(), |
| 89 &program); | 79 &program); |
| 90 | 80 |
| 91 if (parse_status != courgette::C_OK) | 81 if (parse_status != courgette::C_OK) |
| 92 Problem("Can't parse input."); | 82 Problem("Can't parse input."); |
| 93 | 83 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 108 | 98 |
| 109 courgette::DeleteEncodedProgram(encoded); | 99 courgette::DeleteEncodedProgram(encoded); |
| 110 | 100 |
| 111 courgette::SinkStream sink; | 101 courgette::SinkStream sink; |
| 112 if (!sinks.CopyTo(&sink)) | 102 if (!sinks.CopyTo(&sink)) |
| 113 Problem("Can't combine serialized encoded program streams."); | 103 Problem("Can't combine serialized encoded program streams."); |
| 114 | 104 |
| 115 WriteSinkToFile(&sink, output_file); | 105 WriteSinkToFile(&sink, output_file); |
| 116 } | 106 } |
| 117 | 107 |
| 118 void DisassembleAndAdjust(const std::wstring& program_file, | 108 void DisassembleAndAdjust(const FilePath& program_file, |
| 119 const std::wstring& model_file, | 109 const FilePath& model_file, |
| 120 const std::wstring& output_file) { | 110 const FilePath& output_file) { |
| 121 std::string program_buffer = ReadOrFail(program_file, "program"); | 111 std::string program_buffer = ReadOrFail(program_file, "program"); |
| 122 std::string model_buffer = ReadOrFail(model_file, "reference"); | 112 std::string model_buffer = ReadOrFail(model_file, "reference"); |
| 123 | 113 |
| 124 courgette::AssemblyProgram* program = NULL; | 114 courgette::AssemblyProgram* program = NULL; |
| 125 const courgette::Status parse_program_status = | 115 const courgette::Status parse_program_status = |
| 126 courgette::ParseDetectedExecutable(program_buffer.c_str(), | 116 courgette::ParseDetectedExecutable(program_buffer.c_str(), |
| 127 program_buffer.length(), | 117 program_buffer.length(), |
| 128 &program); | 118 &program); |
| 129 if (parse_program_status != courgette::C_OK) | 119 if (parse_program_status != courgette::C_OK) |
| 130 Problem("Can't parse program input."); | 120 Problem("Can't parse program input."); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 Problem("Can't combine serialized encoded program streams."); | 153 Problem("Can't combine serialized encoded program streams."); |
| 164 | 154 |
| 165 WriteSinkToFile(&sink, output_file); | 155 WriteSinkToFile(&sink, output_file); |
| 166 } | 156 } |
| 167 | 157 |
| 168 // Diffs two executable files, write a set of files for the diff, one file per | 158 // Diffs two executable files, write a set of files for the diff, one file per |
| 169 // stream of the EncodedProgram format. Each file is the bsdiff between the | 159 // stream of the EncodedProgram format. Each file is the bsdiff between the |
| 170 // original file's stream and the new file's stream. This is completely | 160 // original file's stream and the new file's stream. This is completely |
| 171 // uninteresting to users, but it is handy for seeing how much each which | 161 // uninteresting to users, but it is handy for seeing how much each which |
| 172 // streams are contributing to the final file size. Adjustment is optional. | 162 // streams are contributing to the final file size. Adjustment is optional. |
| 173 void DisassembleAdjustDiff(const std::wstring& model_file, | 163 void DisassembleAdjustDiff(const FilePath& model_file, |
| 174 const std::wstring& program_file, | 164 const FilePath& program_file, |
| 175 const std::wstring& output_file_root, | 165 const FilePath& output_file_root, |
| 176 bool adjust) { | 166 bool adjust) { |
| 177 std::string model_buffer = ReadOrFail(model_file, "'old'"); | 167 std::string model_buffer = ReadOrFail(model_file, "'old'"); |
| 178 std::string program_buffer = ReadOrFail(program_file, "'new'"); | 168 std::string program_buffer = ReadOrFail(program_file, "'new'"); |
| 179 | 169 |
| 180 courgette::AssemblyProgram* model = NULL; | 170 courgette::AssemblyProgram* model = NULL; |
| 181 const courgette::Status parse_model_status = | 171 const courgette::Status parse_model_status = |
| 182 courgette::ParseDetectedExecutable(model_buffer.c_str(), | 172 courgette::ParseDetectedExecutable(model_buffer.c_str(), |
| 183 model_buffer.length(), | 173 model_buffer.length(), |
| 184 &model); | 174 &model); |
| 185 if (parse_model_status != courgette::C_OK) | 175 if (parse_model_status != courgette::C_OK) |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 | 225 |
| 236 courgette::SourceStream old_source; | 226 courgette::SourceStream old_source; |
| 237 courgette::SourceStream new_source; | 227 courgette::SourceStream new_source; |
| 238 old_source.Init(old_stream ? *old_stream : empty_sink); | 228 old_source.Init(old_stream ? *old_stream : empty_sink); |
| 239 new_source.Init(new_stream ? *new_stream : empty_sink); | 229 new_source.Init(new_stream ? *new_stream : empty_sink); |
| 240 courgette::SinkStream patch_stream; | 230 courgette::SinkStream patch_stream; |
| 241 courgette::BSDiffStatus status = | 231 courgette::BSDiffStatus status = |
| 242 courgette::CreateBinaryPatch(&old_source, &new_source, &patch_stream); | 232 courgette::CreateBinaryPatch(&old_source, &new_source, &patch_stream); |
| 243 if (status != courgette::OK) Problem("-xxx failed."); | 233 if (status != courgette::OK) Problem("-xxx failed."); |
| 244 | 234 |
| 235 std::string append = std::string("-") + base::IntToString(i); |
| 236 |
| 245 WriteSinkToFile(&patch_stream, | 237 WriteSinkToFile(&patch_stream, |
| 246 output_file_root + L"-" + UTF8ToWide(base::IntToString(i))); | 238 output_file_root.InsertBeforeExtensionASCII(append)); |
| 247 } | 239 } |
| 248 } | 240 } |
| 249 | 241 |
| 250 void Assemble(const std::wstring& input_file, | 242 void Assemble(const FilePath& input_file, |
| 251 const std::wstring& output_file) { | 243 const FilePath& output_file) { |
| 252 std::string buffer = ReadOrFail(input_file, "input"); | 244 std::string buffer = ReadOrFail(input_file, "input"); |
| 253 | 245 |
| 254 courgette::SourceStreamSet sources; | 246 courgette::SourceStreamSet sources; |
| 255 if (!sources.Init(buffer.c_str(), buffer.length())) | 247 if (!sources.Init(buffer.c_str(), buffer.length())) |
| 256 Problem("Bad input file."); | 248 Problem("Bad input file."); |
| 257 | 249 |
| 258 courgette::EncodedProgram* encoded = NULL; | 250 courgette::EncodedProgram* encoded = NULL; |
| 259 const courgette::Status read_status = ReadEncodedProgram(&sources, &encoded); | 251 const courgette::Status read_status = ReadEncodedProgram(&sources, &encoded); |
| 260 if (read_status != courgette::C_OK) | 252 if (read_status != courgette::C_OK) |
| 261 Problem("Bad encoded program."); | 253 Problem("Bad encoded program."); |
| 262 | 254 |
| 263 courgette::SinkStream sink; | 255 courgette::SinkStream sink; |
| 264 | 256 |
| 265 const courgette::Status assemble_status = courgette::Assemble(encoded, &sink); | 257 const courgette::Status assemble_status = courgette::Assemble(encoded, &sink); |
| 266 if (assemble_status != courgette::C_OK) | 258 if (assemble_status != courgette::C_OK) |
| 267 Problem("Can't assemble."); | 259 Problem("Can't assemble."); |
| 268 | 260 |
| 269 WriteSinkToFile(&sink, output_file); | 261 WriteSinkToFile(&sink, output_file); |
| 270 } | 262 } |
| 271 | 263 |
| 272 void GenerateEnsemblePatch(const std::wstring& old_file, | 264 void GenerateEnsemblePatch(const FilePath& old_file, |
| 273 const std::wstring& new_file, | 265 const FilePath& new_file, |
| 274 const std::wstring& patch_file) { | 266 const FilePath& patch_file) { |
| 275 std::string old_buffer = ReadOrFail(old_file, "'old' input"); | 267 std::string old_buffer = ReadOrFail(old_file, "'old' input"); |
| 276 std::string new_buffer = ReadOrFail(new_file, "'new' input"); | 268 std::string new_buffer = ReadOrFail(new_file, "'new' input"); |
| 277 | 269 |
| 278 courgette::SourceStream old_stream; | 270 courgette::SourceStream old_stream; |
| 279 courgette::SourceStream new_stream; | 271 courgette::SourceStream new_stream; |
| 280 old_stream.Init(old_buffer); | 272 old_stream.Init(old_buffer); |
| 281 new_stream.Init(new_buffer); | 273 new_stream.Init(new_buffer); |
| 282 | 274 |
| 283 courgette::SinkStream patch_stream; | 275 courgette::SinkStream patch_stream; |
| 284 courgette::Status status = | 276 courgette::Status status = |
| 285 courgette::GenerateEnsemblePatch(&old_stream, &new_stream, &patch_stream); | 277 courgette::GenerateEnsemblePatch(&old_stream, &new_stream, &patch_stream); |
| 286 | 278 |
| 287 if (status != courgette::C_OK) Problem("-gen failed."); | 279 if (status != courgette::C_OK) Problem("-gen failed."); |
| 288 | 280 |
| 289 WriteSinkToFile(&patch_stream, patch_file); | 281 WriteSinkToFile(&patch_stream, patch_file); |
| 290 } | 282 } |
| 291 | 283 |
| 292 void ApplyEnsemblePatch(const std::wstring& old_file, | 284 void ApplyEnsemblePatch(const FilePath& old_file, |
| 293 const std::wstring& patch_file, | 285 const FilePath& patch_file, |
| 294 const std::wstring& new_file) { | 286 const FilePath& new_file) { |
| 295 // We do things a little differently here in order to call the same Courgette | 287 // We do things a little differently here in order to call the same Courgette |
| 296 // entry point as the installer. That entry point point takes file names and | 288 // entry point as the installer. That entry point point takes file names and |
| 297 // returns an status code but does not output any diagnostics. | 289 // returns an status code but does not output any diagnostics. |
| 298 #if defined(OS_WIN) | |
| 299 FilePath old_path(old_file); | |
| 300 FilePath patch_path(patch_file); | |
| 301 FilePath new_path(new_file); | |
| 302 #else | |
| 303 FilePath old_path(WideToASCII(old_file)); | |
| 304 FilePath patch_path(WideToASCII(patch_file)); | |
| 305 FilePath new_path(WideToASCII(new_file)); | |
| 306 #endif | |
| 307 | 290 |
| 308 courgette::Status status = | 291 courgette::Status status = |
| 309 courgette::ApplyEnsemblePatch(old_path.value().c_str(), | 292 courgette::ApplyEnsemblePatch(old_file.value().c_str(), |
| 310 patch_path.value().c_str(), | 293 patch_file.value().c_str(), |
| 311 new_path.value().c_str()); | 294 new_file.value().c_str()); |
| 312 | 295 |
| 313 if (status == courgette::C_OK) | 296 if (status == courgette::C_OK) |
| 314 return; | 297 return; |
| 315 | 298 |
| 316 // Diagnose the error. | 299 // Diagnose the error. |
| 317 switch (status) { | 300 switch (status) { |
| 318 case courgette::C_BAD_ENSEMBLE_MAGIC: | 301 case courgette::C_BAD_ENSEMBLE_MAGIC: |
| 319 Problem("Not a courgette patch"); | 302 Problem("Not a courgette patch"); |
| 320 break; | 303 break; |
| 321 | 304 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 348 | 331 |
| 349 // Non-input related errors: | 332 // Non-input related errors: |
| 350 if (status == courgette::C_WRITE_OPEN_ERROR) | 333 if (status == courgette::C_WRITE_OPEN_ERROR) |
| 351 Problem("Can't open output"); | 334 Problem("Can't open output"); |
| 352 if (status == courgette::C_WRITE_ERROR) | 335 if (status == courgette::C_WRITE_ERROR) |
| 353 Problem("Can't write output"); | 336 Problem("Can't write output"); |
| 354 | 337 |
| 355 Problem("-apply failed."); | 338 Problem("-apply failed."); |
| 356 } | 339 } |
| 357 | 340 |
| 358 void GenerateBSDiffPatch(const std::wstring& old_file, | 341 void GenerateBSDiffPatch(const FilePath& old_file, |
| 359 const std::wstring& new_file, | 342 const FilePath& new_file, |
| 360 const std::wstring& patch_file) { | 343 const FilePath& patch_file) { |
| 361 std::string old_buffer = ReadOrFail(old_file, "'old' input"); | 344 std::string old_buffer = ReadOrFail(old_file, "'old' input"); |
| 362 std::string new_buffer = ReadOrFail(new_file, "'new' input"); | 345 std::string new_buffer = ReadOrFail(new_file, "'new' input"); |
| 363 | 346 |
| 364 courgette::SourceStream old_stream; | 347 courgette::SourceStream old_stream; |
| 365 courgette::SourceStream new_stream; | 348 courgette::SourceStream new_stream; |
| 366 old_stream.Init(old_buffer); | 349 old_stream.Init(old_buffer); |
| 367 new_stream.Init(new_buffer); | 350 new_stream.Init(new_buffer); |
| 368 | 351 |
| 369 courgette::SinkStream patch_stream; | 352 courgette::SinkStream patch_stream; |
| 370 courgette::BSDiffStatus status = | 353 courgette::BSDiffStatus status = |
| 371 courgette::CreateBinaryPatch(&old_stream, &new_stream, &patch_stream); | 354 courgette::CreateBinaryPatch(&old_stream, &new_stream, &patch_stream); |
| 372 | 355 |
| 373 if (status != courgette::OK) Problem("-genbsdiff failed."); | 356 if (status != courgette::OK) Problem("-genbsdiff failed."); |
| 374 | 357 |
| 375 WriteSinkToFile(&patch_stream, patch_file); | 358 WriteSinkToFile(&patch_stream, patch_file); |
| 376 } | 359 } |
| 377 | 360 |
| 378 void ApplyBSDiffPatch(const std::wstring& old_file, | 361 void ApplyBSDiffPatch(const FilePath& old_file, |
| 379 const std::wstring& patch_file, | 362 const FilePath& patch_file, |
| 380 const std::wstring& new_file) { | 363 const FilePath& new_file) { |
| 381 std::string old_buffer = ReadOrFail(old_file, "'old' input"); | 364 std::string old_buffer = ReadOrFail(old_file, "'old' input"); |
| 382 std::string patch_buffer = ReadOrFail(patch_file, "'patch' input"); | 365 std::string patch_buffer = ReadOrFail(patch_file, "'patch' input"); |
| 383 | 366 |
| 384 courgette::SourceStream old_stream; | 367 courgette::SourceStream old_stream; |
| 385 courgette::SourceStream patch_stream; | 368 courgette::SourceStream patch_stream; |
| 386 old_stream.Init(old_buffer); | 369 old_stream.Init(old_buffer); |
| 387 patch_stream.Init(patch_buffer); | 370 patch_stream.Init(patch_buffer); |
| 388 | 371 |
| 389 courgette::SinkStream new_stream; | 372 courgette::SinkStream new_stream; |
| 390 courgette::BSDiffStatus status = | 373 courgette::BSDiffStatus status = |
| (...skipping 20 matching lines...) Expand all Loading... |
| 411 bool cmd_dis = command_line.HasSwitch("dis"); | 394 bool cmd_dis = command_line.HasSwitch("dis"); |
| 412 bool cmd_asm = command_line.HasSwitch("asm"); | 395 bool cmd_asm = command_line.HasSwitch("asm"); |
| 413 bool cmd_disadj = command_line.HasSwitch("disadj"); | 396 bool cmd_disadj = command_line.HasSwitch("disadj"); |
| 414 bool cmd_make_patch = command_line.HasSwitch("gen"); | 397 bool cmd_make_patch = command_line.HasSwitch("gen"); |
| 415 bool cmd_apply_patch = command_line.HasSwitch("apply"); | 398 bool cmd_apply_patch = command_line.HasSwitch("apply"); |
| 416 bool cmd_make_bsdiff_patch = command_line.HasSwitch("genbsdiff"); | 399 bool cmd_make_bsdiff_patch = command_line.HasSwitch("genbsdiff"); |
| 417 bool cmd_apply_bsdiff_patch = command_line.HasSwitch("applybsdiff"); | 400 bool cmd_apply_bsdiff_patch = command_line.HasSwitch("applybsdiff"); |
| 418 bool cmd_spread_1_adjusted = command_line.HasSwitch("gen1a"); | 401 bool cmd_spread_1_adjusted = command_line.HasSwitch("gen1a"); |
| 419 bool cmd_spread_1_unadjusted = command_line.HasSwitch("gen1u"); | 402 bool cmd_spread_1_unadjusted = command_line.HasSwitch("gen1u"); |
| 420 | 403 |
| 421 // TODO(evanm): this whole file should use FilePaths instead of wstrings. | 404 std::vector<FilePath> values; |
| 422 std::vector<std::wstring> values; | |
| 423 const CommandLine::StringVector& args = command_line.GetArgs(); | 405 const CommandLine::StringVector& args = command_line.GetArgs(); |
| 424 for (size_t i = 0; i < args.size(); ++i) { | 406 for (size_t i = 0; i < args.size(); ++i) { |
| 425 #if defined(OS_WIN) | 407 values.push_back(FilePath(args[i])); |
| 426 values.push_back(args[i]); | |
| 427 #else | |
| 428 values.push_back(ASCIIToWide(args[i])); | |
| 429 #endif | |
| 430 } | 408 } |
| 431 | 409 |
| 432 // '-repeat=N' is for debugging. Running many iterations can reveal leaks and | 410 // '-repeat=N' is for debugging. Running many iterations can reveal leaks and |
| 433 // bugs in cleanup. | 411 // bugs in cleanup. |
| 434 int repeat_count = 1; | 412 int repeat_count = 1; |
| 435 std::string repeat_switch = command_line.GetSwitchValueASCII("repeat"); | 413 std::string repeat_switch = command_line.GetSwitchValueASCII("repeat"); |
| 436 if (!repeat_switch.empty()) | 414 if (!repeat_switch.empty()) |
| 437 if (!base::StringToInt(repeat_switch, &repeat_count)) | 415 if (!base::StringToInt(repeat_switch, &repeat_count)) |
| 438 repeat_count = 1; | 416 repeat_count = 1; |
| 439 | 417 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 477 } else if (cmd_spread_1_adjusted || cmd_spread_1_unadjusted) { | 455 } else if (cmd_spread_1_adjusted || cmd_spread_1_unadjusted) { |
| 478 if (values.size() != 3) | 456 if (values.size() != 3) |
| 479 UsageProblem("-gen1[au] <old_file> <new_file> <patch_files_root>"); | 457 UsageProblem("-gen1[au] <old_file> <new_file> <patch_files_root>"); |
| 480 DisassembleAdjustDiff(values[0], values[1], values[2], | 458 DisassembleAdjustDiff(values[0], values[1], values[2], |
| 481 cmd_spread_1_adjusted); | 459 cmd_spread_1_adjusted); |
| 482 } else { | 460 } else { |
| 483 UsageProblem("No operation specified"); | 461 UsageProblem("No operation specified"); |
| 484 } | 462 } |
| 485 } | 463 } |
| 486 } | 464 } |
| OLD | NEW |