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 |