chrome_content_utility_client.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/utility/chrome_content_utility_client.h"
6
7#include "base/base64.h"
8#include "base/bind.h"
9#include "base/command_line.h"
10#include "base/json/json_reader.h"
11#include "base/memory/ref_counted.h"
12#include "base/memory/scoped_ptr.h"
13#include "chrome/common/chrome_utility_messages.h"
14#include "chrome/common/extensions/chrome_manifest_handlers.h"
15#include "chrome/common/extensions/extension.h"
16#include "chrome/common/extensions/extension_l10n_util.h"
17#include "chrome/common/extensions/manifest.h"
18#include "chrome/common/extensions/permissions/chrome_api_permissions.h"
19#include "chrome/common/extensions/update_manifest.h"
20#include "chrome/common/safe_browsing/zip_analyzer.h"
21#include "chrome/utility/extensions/unpacker.h"
22#include "chrome/utility/profile_import_handler.h"
23#include "chrome/utility/web_resource_unpacker.h"
24#include "content/public/child/image_decoder_utils.h"
25#include "content/public/utility/utility_thread.h"
26#include "printing/page_range.h"
27#include "third_party/skia/include/core/SkBitmap.h"
28#include "third_party/zlib/google/zip.h"
29#include "ui/base/ui_base_switches.h"
30#include "ui/gfx/codec/jpeg_codec.h"
31#include "ui/gfx/rect.h"
32#include "ui/gfx/size.h"
33
34#if defined(OS_WIN)
35#include "base/file_util.h"
36#include "base/path_service.h"
37#include "base/win/iat_patch_function.h"
38#include "base/win/scoped_handle.h"
39#include "chrome/common/chrome_paths.h"
40#include "chrome/utility/itunes_pref_parser_win.h"
41#include "printing/emf_win.h"
42#include "ui/gfx/gdi_util.h"
43#endif  // defined(OS_WIN)
44
45#if defined(OS_WIN) || defined(OS_MACOSX)
46#include "chrome/common/media_galleries/picasa_types.h"
47#include "chrome/utility/itunes_library_parser.h"
48#include "chrome/utility/media_galleries/picasa_album_table_reader.h"
49#endif  // defined(OS_WIN) || defined(OS_MACOSX)
50
51#if defined(ENABLE_PRINTING)
52#include "chrome/common/child_process_logging.h"
53#include "printing/backend/print_backend.h"
54#endif
55
56#if defined(ENABLE_MDNS)
57#include "chrome/utility/local_discovery/service_discovery_message_handler.h"
58#endif  // ENABLE_MDNS
59
60namespace chrome {
61
62namespace {
63
64bool Send(IPC::Message* message) {
65  return content::UtilityThread::Get()->Send(message);
66}
67
68void ReleaseProcessIfNeeded() {
69  content::UtilityThread::Get()->ReleaseProcessIfNeeded();
70}
71
72}  // namespace
73
74ChromeContentUtilityClient::ChromeContentUtilityClient() {
75#if !defined(OS_ANDROID)
76  handlers_.push_back(new ProfileImportHandler());
77#endif  // OS_ANDROID
78
79#if defined(ENABLE_MDNS)
80  handlers_.push_back(new local_discovery::ServiceDiscoveryMessageHandler());
81#endif  // ENABLE_MDNS
82}
83
84ChromeContentUtilityClient::~ChromeContentUtilityClient() {
85}
86
87void ChromeContentUtilityClient::UtilityThreadStarted() {
88#if defined(OS_WIN)
89  // Load the pdf plugin before the sandbox is turned on. This is for Windows
90  // only because we need this DLL only on Windows.
91  base::FilePath pdf;
92  if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) &&
93      base::PathExists(pdf)) {
94    bool rv = !!LoadLibrary(pdf.value().c_str());
95    DCHECK(rv) << "Couldn't load PDF plugin";
96  }
97#endif
98
99  CommandLine* command_line = CommandLine::ForCurrentProcess();
100  std::string lang = command_line->GetSwitchValueASCII(switches::kLang);
101  if (!lang.empty())
102    extension_l10n_util::SetProcessLocale(lang);
103}
104
105bool ChromeContentUtilityClient::OnMessageReceived(
106    const IPC::Message& message) {
107  bool handled = true;
108  IPC_BEGIN_MESSAGE_MAP(ChromeContentUtilityClient, message)
109    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackExtension, OnUnpackExtension)
110    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackWebResource,
111                        OnUnpackWebResource)
112    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseUpdateManifest,
113                        OnParseUpdateManifest)
114    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImage, OnDecodeImage)
115    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImageBase64, OnDecodeImageBase64)
116    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafile,
117                        OnRenderPDFPagesToMetafile)
118    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RobustJPEGDecodeImage,
119                        OnRobustJPEGDecodeImage)
120    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseJSON, OnParseJSON)
121    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_GetPrinterCapsAndDefaults,
122                        OnGetPrinterCapsAndDefaults)
123    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing, OnStartupPing)
124    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection,
125                        OnAnalyzeZipFileForDownloadProtection)
126
127#if defined(OS_CHROMEOS)
128    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile)
129#endif  // defined(OS_CHROMEOS)
130
131#if defined(OS_WIN)
132    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseITunesPrefXml,
133                        OnParseITunesPrefXml)
134#endif  // defined(OS_WIN)
135
136#if defined(OS_WIN) || defined(OS_MACOSX)
137    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseITunesLibraryXmlFile,
138                        OnParseITunesLibraryXmlFile)
139    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParsePicasaPMPDatabase,
140                        OnParsePicasaPMPDatabase)
141#endif  // defined(OS_WIN) || defined(OS_MACOSX)
142
143    IPC_MESSAGE_UNHANDLED(handled = false)
144  IPC_END_MESSAGE_MAP()
145
146  for (Handlers::iterator it = handlers_.begin();
147       !handled && it != handlers_.end(); ++it) {
148    handled = (*it)->OnMessageReceived(message);
149  }
150
151  return handled;
152}
153
154void ChromeContentUtilityClient::PreSandboxStartup() {
155#if defined(ENABLE_MDNS)
156  local_discovery::ServiceDiscoveryMessageHandler::PreSandboxStartup();
157#endif  // ENABLE_MDNS
158}
159
160void ChromeContentUtilityClient::OnUnpackExtension(
161    const base::FilePath& extension_path,
162    const std::string& extension_id,
163    int location,
164    int creation_flags) {
165  CHECK_GT(location, extensions::Manifest::INVALID_LOCATION);
166  CHECK_LT(location, extensions::Manifest::NUM_LOCATIONS);
167  extensions::PermissionsInfo::GetInstance()->InitializeWithDelegate(
168      extensions::ChromeAPIPermissions());
169  extensions::RegisterChromeManifestHandlers();
170  extensions::Unpacker unpacker(
171      extension_path,
172      extension_id,
173      static_cast<extensions::Manifest::Location>(location),
174      creation_flags);
175  if (unpacker.Run() && unpacker.DumpImagesToFile() &&
176      unpacker.DumpMessageCatalogsToFile()) {
177    Send(new ChromeUtilityHostMsg_UnpackExtension_Succeeded(
178        *unpacker.parsed_manifest()));
179  } else {
180    Send(new ChromeUtilityHostMsg_UnpackExtension_Failed(
181        unpacker.error_message()));
182  }
183
184  ReleaseProcessIfNeeded();
185}
186
187void ChromeContentUtilityClient::OnUnpackWebResource(
188    const std::string& resource_data) {
189  // Parse json data.
190  // TODO(mrc): Add the possibility of a template that controls parsing, and
191  // the ability to download and verify images.
192  WebResourceUnpacker unpacker(resource_data);
193  if (unpacker.Run()) {
194    Send(new ChromeUtilityHostMsg_UnpackWebResource_Succeeded(
195        *unpacker.parsed_json()));
196  } else {
197    Send(new ChromeUtilityHostMsg_UnpackWebResource_Failed(
198        unpacker.error_message()));
199  }
200
201  ReleaseProcessIfNeeded();
202}
203
204void ChromeContentUtilityClient::OnParseUpdateManifest(const std::string& xml) {
205  UpdateManifest manifest;
206  if (!manifest.Parse(xml)) {
207    Send(new ChromeUtilityHostMsg_ParseUpdateManifest_Failed(
208        manifest.errors()));
209  } else {
210    Send(new ChromeUtilityHostMsg_ParseUpdateManifest_Succeeded(
211        manifest.results()));
212  }
213  ReleaseProcessIfNeeded();
214}
215
216void ChromeContentUtilityClient::OnDecodeImage(
217    const std::vector<unsigned char>& encoded_data) {
218  const SkBitmap& decoded_image = content::DecodeImage(&encoded_data[0],
219                                                       gfx::Size(),
220                                                       encoded_data.size());
221  if (decoded_image.empty()) {
222    Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
223  } else {
224    Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(decoded_image));
225  }
226  ReleaseProcessIfNeeded();
227}
228
229void ChromeContentUtilityClient::OnDecodeImageBase64(
230    const std::string& encoded_string) {
231  std::string decoded_string;
232
233  if (!base::Base64Decode(encoded_string, &decoded_string)) {
234    Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
235    return;
236  }
237
238  std::vector<unsigned char> decoded_vector(decoded_string.size());
239  for (size_t i = 0; i < decoded_string.size(); ++i) {
240    decoded_vector[i] = static_cast<unsigned char>(decoded_string[i]);
241  }
242
243  OnDecodeImage(decoded_vector);
244}
245
246#if defined(OS_CHROMEOS)
247void ChromeContentUtilityClient::OnCreateZipFile(
248    const base::FilePath& src_dir,
249    const std::vector<base::FilePath>& src_relative_paths,
250    const base::FileDescriptor& dest_fd) {
251  bool succeeded = true;
252
253  // Check sanity of source relative paths. Reject if path is absolute or
254  // contains any attempt to reference a parent directory ("../" tricks).
255  for (std::vector<base::FilePath>::const_iterator iter =
256           src_relative_paths.begin(); iter != src_relative_paths.end();
257       ++iter) {
258    if (iter->IsAbsolute() || iter->ReferencesParent()) {
259      succeeded = false;
260      break;
261    }
262  }
263
264  if (succeeded)
265    succeeded = zip::ZipFiles(src_dir, src_relative_paths, dest_fd.fd);
266
267  if (succeeded)
268    Send(new ChromeUtilityHostMsg_CreateZipFile_Succeeded());
269  else
270    Send(new ChromeUtilityHostMsg_CreateZipFile_Failed());
271  ReleaseProcessIfNeeded();
272}
273#endif  // defined(OS_CHROMEOS)
274
275void ChromeContentUtilityClient::OnRenderPDFPagesToMetafile(
276    base::PlatformFile pdf_file,
277    const base::FilePath& metafile_path,
278    const printing::PdfRenderSettings& pdf_render_settings,
279    const std::vector<printing::PageRange>& page_ranges) {
280  bool succeeded = false;
281#if defined(OS_WIN)
282  int highest_rendered_page_number = 0;
283  double scale_factor = 1.0;
284  succeeded = RenderPDFToWinMetafile(pdf_file,
285                                     metafile_path,
286                                     pdf_render_settings.area(),
287                                     pdf_render_settings.dpi(),
288                                     pdf_render_settings.autorotate(),
289                                     page_ranges,
290                                     &highest_rendered_page_number,
291                                     &scale_factor);
292  if (succeeded) {
293    Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Succeeded(
294        highest_rendered_page_number, scale_factor));
295  }
296#endif  // defined(OS_WIN)
297  if (!succeeded) {
298    Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Failed());
299  }
300  ReleaseProcessIfNeeded();
301}
302
303#if defined(OS_WIN)
304// Exported by pdf.dll
305typedef bool (*RenderPDFPageToDCProc)(
306    const unsigned char* pdf_buffer, int buffer_size, int page_number, HDC dc,
307    int dpi_x, int dpi_y, int bounds_origin_x, int bounds_origin_y,
308    int bounds_width, int bounds_height, bool fit_to_bounds,
309    bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds,
310    bool autorotate);
311
312typedef bool (*GetPDFDocInfoProc)(const unsigned char* pdf_buffer,
313                                  int buffer_size, int* page_count,
314                                  double* max_page_width);
315
316// The 2 below IAT patch functions are almost identical to the code in
317// render_process_impl.cc. This is needed to work around specific Windows APIs
318// used by the Chrome PDF plugin that will fail in the sandbox.
319static base::win::IATPatchFunction g_iat_patch_createdca;
320HDC WINAPI UtilityProcess_CreateDCAPatch(LPCSTR driver_name,
321                                         LPCSTR device_name,
322                                         LPCSTR output,
323                                         const DEVMODEA* init_data) {
324  if (driver_name &&
325      (std::string("DISPLAY") == std::string(driver_name)))
326  // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
327    return CreateCompatibleDC(NULL);
328
329  NOTREACHED();
330  return CreateDCA(driver_name, device_name, output, init_data);
331}
332
333static base::win::IATPatchFunction g_iat_patch_get_font_data;
334DWORD WINAPI UtilityProcess_GetFontDataPatch(
335    HDC hdc, DWORD table, DWORD offset, LPVOID buffer, DWORD length) {
336  int rv = GetFontData(hdc, table, offset, buffer, length);
337  if (rv == GDI_ERROR && hdc) {
338    HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));
339
340    LOGFONT logfont;
341    if (GetObject(font, sizeof(LOGFONT), &logfont)) {
342      std::vector<char> font_data;
343      content::UtilityThread::Get()->PreCacheFont(logfont);
344      rv = GetFontData(hdc, table, offset, buffer, length);
345      content::UtilityThread::Get()->ReleaseCachedFonts();
346    }
347  }
348  return rv;
349}
350
351bool ChromeContentUtilityClient::RenderPDFToWinMetafile(
352    base::PlatformFile pdf_file,
353    const base::FilePath& metafile_path,
354    const gfx::Rect& render_area,
355    int render_dpi,
356    bool autorotate,
357    const std::vector<printing::PageRange>& page_ranges,
358    int* highest_rendered_page_number,
359    double* scale_factor) {
360  *highest_rendered_page_number = -1;
361  *scale_factor = 1.0;
362  base::win::ScopedHandle file(pdf_file);
363  base::FilePath pdf_module_path;
364  PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_module_path);
365  HMODULE pdf_module = GetModuleHandle(pdf_module_path.value().c_str());
366  if (!pdf_module)
367    return false;
368
369  RenderPDFPageToDCProc render_proc =
370      reinterpret_cast<RenderPDFPageToDCProc>(
371          GetProcAddress(pdf_module, "RenderPDFPageToDC"));
372  if (!render_proc)
373    return false;
374
375  GetPDFDocInfoProc get_info_proc = reinterpret_cast<GetPDFDocInfoProc>(
376          GetProcAddress(pdf_module, "GetPDFDocInfo"));
377  if (!get_info_proc)
378    return false;
379
380  // Patch the IAT for handling specific APIs known to fail in the sandbox.
381  if (!g_iat_patch_createdca.is_patched())
382    g_iat_patch_createdca.Patch(pdf_module_path.value().c_str(),
383                                "gdi32.dll", "CreateDCA",
384                                UtilityProcess_CreateDCAPatch);
385
386  if (!g_iat_patch_get_font_data.is_patched())
387    g_iat_patch_get_font_data.Patch(pdf_module_path.value().c_str(),
388                                    "gdi32.dll", "GetFontData",
389                                    UtilityProcess_GetFontDataPatch);
390
391  // TODO(sanjeevr): Add a method to the PDF DLL that takes in a file handle
392  // and a page range array. That way we don't need to read the entire PDF into
393  // memory.
394  DWORD length = ::GetFileSize(file, NULL);
395  if (length == INVALID_FILE_SIZE)
396    return false;
397
398  std::vector<uint8> buffer;
399  buffer.resize(length);
400  DWORD bytes_read = 0;
401  if (!ReadFile(pdf_file, &buffer.front(), length, &bytes_read, NULL) ||
402      (bytes_read != length))
403    return false;
404
405  int total_page_count = 0;
406  if (!get_info_proc(&buffer.front(), buffer.size(), &total_page_count, NULL))
407    return false;
408
409  printing::Emf metafile;
410  metafile.InitToFile(metafile_path);
411  // We need to scale down DC to fit an entire page into DC available area.
412  // Current metafile is based on screen DC and have current screen size.
413  // Writing outside of those boundaries will result in the cut-off output.
414  // On metafiles (this is the case here), scaling down will still record
415  // original coordinates and we'll be able to print in full resolution.
416  // Before playback we'll need to counter the scaling up that will happen
417  // in the service (print_system_win.cc).
418  *scale_factor = gfx::CalculatePageScale(metafile.context(),
419                                          render_area.right(),
420                                          render_area.bottom());
421  gfx::ScaleDC(metafile.context(), *scale_factor);
422
423  bool ret = false;
424  std::vector<printing::PageRange>::const_iterator iter;
425  for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) {
426    for (int page_number = iter->from; page_number <= iter->to; ++page_number) {
427      if (page_number >= total_page_count)
428        break;
429      // The underlying metafile is of type Emf and ignores the arguments passed
430      // to StartPage.
431      metafile.StartPage(gfx::Size(), gfx::Rect(), 1);
432      if (render_proc(&buffer.front(), buffer.size(), page_number,
433                      metafile.context(), render_dpi, render_dpi,
434                      render_area.x(), render_area.y(), render_area.width(),
435                      render_area.height(), true, false, true, true,
436                      autorotate))
437        if (*highest_rendered_page_number < page_number)
438          *highest_rendered_page_number = page_number;
439        ret = true;
440      metafile.FinishPage();
441    }
442  }
443  metafile.FinishDocument();
444  return ret;
445}
446#endif  // defined(OS_WIN)
447
448void ChromeContentUtilityClient::OnRobustJPEGDecodeImage(
449    const std::vector<unsigned char>& encoded_data) {
450  // Our robust jpeg decoding is using IJG libjpeg.
451  if (gfx::JPEGCodec::JpegLibraryVariant() == gfx::JPEGCodec::IJG_LIBJPEG) {
452    scoped_ptr<SkBitmap> decoded_image(gfx::JPEGCodec::Decode(
453        &encoded_data[0], encoded_data.size()));
454    if (!decoded_image.get() || decoded_image->empty()) {
455      Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
456    } else {
457      Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(*decoded_image));
458    }
459  } else {
460    Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
461  }
462  ReleaseProcessIfNeeded();
463}
464
465void ChromeContentUtilityClient::OnParseJSON(const std::string& json) {
466  int error_code;
467  std::string error;
468  base::Value* value = base::JSONReader::ReadAndReturnError(
469      json, base::JSON_PARSE_RFC, &error_code, &error);
470  if (value) {
471    base::ListValue wrapper;
472    wrapper.Append(value);
473    Send(new ChromeUtilityHostMsg_ParseJSON_Succeeded(wrapper));
474  } else {
475    Send(new ChromeUtilityHostMsg_ParseJSON_Failed(error));
476  }
477  ReleaseProcessIfNeeded();
478}
479
480void ChromeContentUtilityClient::OnGetPrinterCapsAndDefaults(
481    const std::string& printer_name) {
482#if defined(ENABLE_PRINTING)
483  scoped_refptr<printing::PrintBackend> print_backend =
484      printing::PrintBackend::CreateInstance(NULL);
485  printing::PrinterCapsAndDefaults printer_info;
486
487  child_process_logging::ScopedPrinterInfoSetter prn_info(
488      print_backend->GetPrinterDriverInfo(printer_name));
489
490  if (print_backend->GetPrinterCapsAndDefaults(printer_name, &printer_info)) {
491    Send(new ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded(
492        printer_name, printer_info));
493  } else  // NOLINT
494#endif
495  {
496    Send(new ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Failed(
497        printer_name));
498  }
499  ReleaseProcessIfNeeded();
500}
501
502void ChromeContentUtilityClient::OnStartupPing() {
503  Send(new ChromeUtilityHostMsg_ProcessStarted);
504  // Don't release the process, we assume further messages are on the way.
505}
506
507void ChromeContentUtilityClient::OnAnalyzeZipFileForDownloadProtection(
508    IPC::PlatformFileForTransit zip_file) {
509  safe_browsing::zip_analyzer::Results results;
510  safe_browsing::zip_analyzer::AnalyzeZipFile(
511      IPC::PlatformFileForTransitToPlatformFile(zip_file), &results);
512  Send(new ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished(
513      results));
514  ReleaseProcessIfNeeded();
515}
516
517#if defined(OS_WIN)
518void ChromeContentUtilityClient::OnParseITunesPrefXml(
519    const std::string& itunes_xml_data) {
520  base::FilePath library_path(
521      itunes::FindLibraryLocationInPrefXml(itunes_xml_data));
522  Send(new ChromeUtilityHostMsg_GotITunesDirectory(library_path));
523  ReleaseProcessIfNeeded();
524}
525#endif  // defined(OS_WIN)
526
527#if defined(OS_WIN) || defined(OS_MACOSX)
528void ChromeContentUtilityClient::OnParseITunesLibraryXmlFile(
529    IPC::PlatformFileForTransit itunes_library_file) {
530  itunes::ITunesLibraryParser parser;
531  base::PlatformFile file =
532      IPC::PlatformFileForTransitToPlatformFile(itunes_library_file);
533  bool result = parser.Parse(
534      itunes::ITunesLibraryParser::ReadITunesLibraryXmlFile(file));
535  Send(new ChromeUtilityHostMsg_GotITunesLibrary(result, parser.library()));
536  ReleaseProcessIfNeeded();
537}
538
539void ChromeContentUtilityClient::OnParsePicasaPMPDatabase(
540    const picasa::AlbumTableFilesForTransit& album_table_files) {
541  picasa::AlbumTableFiles files;
542  files.indicator_file = IPC::PlatformFileForTransitToPlatformFile(
543      album_table_files.indicator_file);
544  files.category_file = IPC::PlatformFileForTransitToPlatformFile(
545      album_table_files.category_file);
546  files.date_file = IPC::PlatformFileForTransitToPlatformFile(
547      album_table_files.date_file);
548  files.filename_file = IPC::PlatformFileForTransitToPlatformFile(
549      album_table_files.filename_file);
550  files.name_file = IPC::PlatformFileForTransitToPlatformFile(
551      album_table_files.name_file);
552  files.token_file = IPC::PlatformFileForTransitToPlatformFile(
553      album_table_files.token_file);
554  files.uid_file = IPC::PlatformFileForTransitToPlatformFile(
555      album_table_files.uid_file);
556
557  picasa::PicasaAlbumTableReader reader(files);
558  bool parse_success = reader.Init();
559  Send(new ChromeUtilityHostMsg_ParsePicasaPMPDatabase_Finished(
560      parse_success,
561      reader.albums(),
562      reader.folders()));
563  ReleaseProcessIfNeeded();
564}
565#endif  // defined(OS_WIN) || defined(OS_MACOSX)
566
567}  // namespace chrome
568