Chromium Code Reviews| 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 FilePath::StringType append = FilePath::StringType("-") + | |
| 236 base::IntToString(i); | |
| 237 | |
| 245 WriteSinkToFile(&patch_stream, | 238 WriteSinkToFile(&patch_stream, |
| 246 output_file_root + L"-" + UTF8ToWide(base::IntToString(i))); | 239 output_file_root.InsertBeforeExtension(append)); |
| 247 } | 240 } |
| 248 } | 241 } |
| 249 | 242 |
| 250 void Assemble(const std::wstring& input_file, | 243 void Assemble(const FilePath& input_file, |
| 251 const std::wstring& output_file) { | 244 const FilePath& output_file) { |
| 252 std::string buffer = ReadOrFail(input_file, "input"); | 245 std::string buffer = ReadOrFail(input_file, "input"); |
| 253 | 246 |
| 254 courgette::SourceStreamSet sources; | 247 courgette::SourceStreamSet sources; |
| 255 if (!sources.Init(buffer.c_str(), buffer.length())) | 248 if (!sources.Init(buffer.c_str(), buffer.length())) |
| 256 Problem("Bad input file."); | 249 Problem("Bad input file."); |
| 257 | 250 |
| 258 courgette::EncodedProgram* encoded = NULL; | 251 courgette::EncodedProgram* encoded = NULL; |
| 259 const courgette::Status read_status = ReadEncodedProgram(&sources, &encoded); | 252 const courgette::Status read_status = ReadEncodedProgram(&sources, &encoded); |
| 260 if (read_status != courgette::C_OK) | 253 if (read_status != courgette::C_OK) |
| 261 Problem("Bad encoded program."); | 254 Problem("Bad encoded program."); |
| 262 | 255 |
| 263 courgette::SinkStream sink; | 256 courgette::SinkStream sink; |
| 264 | 257 |
| 265 const courgette::Status assemble_status = courgette::Assemble(encoded, &sink); | 258 const courgette::Status assemble_status = courgette::Assemble(encoded, &sink); |
| 266 if (assemble_status != courgette::C_OK) | 259 if (assemble_status != courgette::C_OK) |
| 267 Problem("Can't assemble."); | 260 Problem("Can't assemble."); |
| 268 | 261 |
| 269 WriteSinkToFile(&sink, output_file); | 262 WriteSinkToFile(&sink, output_file); |
| 270 } | 263 } |
| 271 | 264 |
| 272 void GenerateEnsemblePatch(const std::wstring& old_file, | 265 void GenerateEnsemblePatch(const FilePath& old_file, |
| 273 const std::wstring& new_file, | 266 const FilePath& new_file, |
| 274 const std::wstring& patch_file) { | 267 const FilePath& patch_file) { |
| 275 std::string old_buffer = ReadOrFail(old_file, "'old' input"); | 268 std::string old_buffer = ReadOrFail(old_file, "'old' input"); |
| 276 std::string new_buffer = ReadOrFail(new_file, "'new' input"); | 269 std::string new_buffer = ReadOrFail(new_file, "'new' input"); |
| 277 | 270 |
| 278 courgette::SourceStream old_stream; | 271 courgette::SourceStream old_stream; |
| 279 courgette::SourceStream new_stream; | 272 courgette::SourceStream new_stream; |
| 280 old_stream.Init(old_buffer); | 273 old_stream.Init(old_buffer); |
| 281 new_stream.Init(new_buffer); | 274 new_stream.Init(new_buffer); |
| 282 | 275 |
| 283 courgette::SinkStream patch_stream; | 276 courgette::SinkStream patch_stream; |
| 284 courgette::Status status = | 277 courgette::Status status = |
| 285 courgette::GenerateEnsemblePatch(&old_stream, &new_stream, &patch_stream); | 278 courgette::GenerateEnsemblePatch(&old_stream, &new_stream, &patch_stream); |
| 286 | 279 |
| 287 if (status != courgette::C_OK) Problem("-gen failed."); | 280 if (status != courgette::C_OK) Problem("-gen failed."); |
| 288 | 281 |
| 289 WriteSinkToFile(&patch_stream, patch_file); | 282 WriteSinkToFile(&patch_stream, patch_file); |
| 290 } | 283 } |
| 291 | 284 |
| 292 void ApplyEnsemblePatch(const std::wstring& old_file, | 285 void ApplyEnsemblePatch(const FilePath& old_file, |
| 293 const std::wstring& patch_file, | 286 const FilePath& patch_file, |
| 294 const std::wstring& new_file) { | 287 const FilePath& new_file) { |
| 295 // We do things a little differently here in order to call the same Courgette | 288 // 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 | 289 // entry point as the installer. That entry point point takes file names and |
| 297 // returns an status code but does not output any diagnostics. | 290 // 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 | 291 |
| 308 courgette::Status status = | 292 courgette::Status status = |
| 309 courgette::ApplyEnsemblePatch(old_path.value().c_str(), | 293 courgette::ApplyEnsemblePatch(old_file.value().c_str(), |
| 310 patch_path.value().c_str(), | 294 patch_file.value().c_str(), |
| 311 new_path.value().c_str()); | 295 new_file.value().c_str()); |
| 312 | 296 |
| 313 if (status == courgette::C_OK) | 297 if (status == courgette::C_OK) |
| 314 return; | 298 return; |
| 315 | 299 |
| 316 // Diagnose the error. | 300 // Diagnose the error. |
| 317 switch (status) { | 301 switch (status) { |
| 318 case courgette::C_BAD_ENSEMBLE_MAGIC: | 302 case courgette::C_BAD_ENSEMBLE_MAGIC: |
| 319 Problem("Not a courgette patch"); | 303 Problem("Not a courgette patch"); |
| 320 break; | 304 break; |
| 321 | 305 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 348 | 332 |
| 349 // Non-input related errors: | 333 // Non-input related errors: |
| 350 if (status == courgette::C_WRITE_OPEN_ERROR) | 334 if (status == courgette::C_WRITE_OPEN_ERROR) |
| 351 Problem("Can't open output"); | 335 Problem("Can't open output"); |
| 352 if (status == courgette::C_WRITE_ERROR) | 336 if (status == courgette::C_WRITE_ERROR) |
| 353 Problem("Can't write output"); | 337 Problem("Can't write output"); |
| 354 | 338 |
| 355 Problem("-apply failed."); | 339 Problem("-apply failed."); |
| 356 } | 340 } |
| 357 | 341 |
| 358 void GenerateBSDiffPatch(const std::wstring& old_file, | 342 void GenerateBSDiffPatch(const FilePath& old_file, |
| 359 const std::wstring& new_file, | 343 const FilePath& new_file, |
| 360 const std::wstring& patch_file) { | 344 const FilePath& patch_file) { |
| 361 std::string old_buffer = ReadOrFail(old_file, "'old' input"); | 345 std::string old_buffer = ReadOrFail(old_file, "'old' input"); |
| 362 std::string new_buffer = ReadOrFail(new_file, "'new' input"); | 346 std::string new_buffer = ReadOrFail(new_file, "'new' input"); |
| 363 | 347 |
| 364 courgette::SourceStream old_stream; | 348 courgette::SourceStream old_stream; |
| 365 courgette::SourceStream new_stream; | 349 courgette::SourceStream new_stream; |
| 366 old_stream.Init(old_buffer); | 350 old_stream.Init(old_buffer); |
| 367 new_stream.Init(new_buffer); | 351 new_stream.Init(new_buffer); |
| 368 | 352 |
| 369 courgette::SinkStream patch_stream; | 353 courgette::SinkStream patch_stream; |
| 370 courgette::BSDiffStatus status = | 354 courgette::BSDiffStatus status = |
| 371 courgette::CreateBinaryPatch(&old_stream, &new_stream, &patch_stream); | 355 courgette::CreateBinaryPatch(&old_stream, &new_stream, &patch_stream); |
| 372 | 356 |
| 373 if (status != courgette::OK) Problem("-genbsdiff failed."); | 357 if (status != courgette::OK) Problem("-genbsdiff failed."); |
| 374 | 358 |
| 375 WriteSinkToFile(&patch_stream, patch_file); | 359 WriteSinkToFile(&patch_stream, patch_file); |
| 376 } | 360 } |
| 377 | 361 |
| 378 void ApplyBSDiffPatch(const std::wstring& old_file, | 362 void ApplyBSDiffPatch(const FilePath& old_file, |
| 379 const std::wstring& patch_file, | 363 const FilePath& patch_file, |
| 380 const std::wstring& new_file) { | 364 const FilePath& new_file) { |
| 381 std::string old_buffer = ReadOrFail(old_file, "'old' input"); | 365 std::string old_buffer = ReadOrFail(old_file, "'old' input"); |
| 382 std::string patch_buffer = ReadOrFail(patch_file, "'patch' input"); | 366 std::string patch_buffer = ReadOrFail(patch_file, "'patch' input"); |
| 383 | 367 |
| 384 courgette::SourceStream old_stream; | 368 courgette::SourceStream old_stream; |
| 385 courgette::SourceStream patch_stream; | 369 courgette::SourceStream patch_stream; |
| 386 old_stream.Init(old_buffer); | 370 old_stream.Init(old_buffer); |
| 387 patch_stream.Init(patch_buffer); | 371 patch_stream.Init(patch_buffer); |
| 388 | 372 |
| 389 courgette::SinkStream new_stream; | 373 courgette::SinkStream new_stream; |
| 390 courgette::BSDiffStatus status = | 374 courgette::BSDiffStatus status = |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 411 bool cmd_dis = command_line.HasSwitch("dis"); | 395 bool cmd_dis = command_line.HasSwitch("dis"); |
| 412 bool cmd_asm = command_line.HasSwitch("asm"); | 396 bool cmd_asm = command_line.HasSwitch("asm"); |
| 413 bool cmd_disadj = command_line.HasSwitch("disadj"); | 397 bool cmd_disadj = command_line.HasSwitch("disadj"); |
| 414 bool cmd_make_patch = command_line.HasSwitch("gen"); | 398 bool cmd_make_patch = command_line.HasSwitch("gen"); |
| 415 bool cmd_apply_patch = command_line.HasSwitch("apply"); | 399 bool cmd_apply_patch = command_line.HasSwitch("apply"); |
| 416 bool cmd_make_bsdiff_patch = command_line.HasSwitch("genbsdiff"); | 400 bool cmd_make_bsdiff_patch = command_line.HasSwitch("genbsdiff"); |
| 417 bool cmd_apply_bsdiff_patch = command_line.HasSwitch("applybsdiff"); | 401 bool cmd_apply_bsdiff_patch = command_line.HasSwitch("applybsdiff"); |
| 418 bool cmd_spread_1_adjusted = command_line.HasSwitch("gen1a"); | 402 bool cmd_spread_1_adjusted = command_line.HasSwitch("gen1a"); |
| 419 bool cmd_spread_1_unadjusted = command_line.HasSwitch("gen1u"); | 403 bool cmd_spread_1_unadjusted = command_line.HasSwitch("gen1u"); |
| 420 | 404 |
| 421 // TODO(evanm): this whole file should use FilePaths instead of wstrings. | 405 std::vector<FilePath> values; |
| 422 std::vector<std::wstring> values; | |
| 423 const CommandLine::StringVector& args = command_line.GetArgs(); | 406 const CommandLine::StringVector& args = command_line.GetArgs(); |
| 424 for (size_t i = 0; i < args.size(); ++i) { | 407 for (size_t i = 0; i < args.size(); ++i) { |
| 425 #if defined(OS_WIN) | 408 #if defined(OS_WIN) |
| 426 values.push_back(args[i]); | 409 values.push_back(FilePath(args[i])); |
| 427 #else | 410 #else |
| 428 values.push_back(ASCIIToWide(args[i])); | 411 values.push_back(FilePath(args[i])); |
|
sra1
2011/11/16 21:04:25
Can remove the #if now.
Just test this runs on Win
dgarrett
2011/11/17 22:44:02
Done.
| |
| 429 #endif | 412 #endif |
| 430 } | 413 } |
| 431 | 414 |
| 432 // '-repeat=N' is for debugging. Running many iterations can reveal leaks and | 415 // '-repeat=N' is for debugging. Running many iterations can reveal leaks and |
| 433 // bugs in cleanup. | 416 // bugs in cleanup. |
| 434 int repeat_count = 1; | 417 int repeat_count = 1; |
| 435 std::string repeat_switch = command_line.GetSwitchValueASCII("repeat"); | 418 std::string repeat_switch = command_line.GetSwitchValueASCII("repeat"); |
| 436 if (!repeat_switch.empty()) | 419 if (!repeat_switch.empty()) |
| 437 if (!base::StringToInt(repeat_switch, &repeat_count)) | 420 if (!base::StringToInt(repeat_switch, &repeat_count)) |
| 438 repeat_count = 1; | 421 repeat_count = 1; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 477 } else if (cmd_spread_1_adjusted || cmd_spread_1_unadjusted) { | 460 } else if (cmd_spread_1_adjusted || cmd_spread_1_unadjusted) { |
| 478 if (values.size() != 3) | 461 if (values.size() != 3) |
| 479 UsageProblem("-gen1[au] <old_file> <new_file> <patch_files_root>"); | 462 UsageProblem("-gen1[au] <old_file> <new_file> <patch_files_root>"); |
| 480 DisassembleAdjustDiff(values[0], values[1], values[2], | 463 DisassembleAdjustDiff(values[0], values[1], values[2], |
| 481 cmd_spread_1_adjusted); | 464 cmd_spread_1_adjusted); |
| 482 } else { | 465 } else { |
| 483 UsageProblem("No operation specified"); | 466 UsageProblem("No operation specified"); |
| 484 } | 467 } |
| 485 } | 468 } |
| 486 } | 469 } |
| OLD | NEW |