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 |