1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file. 4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/utility/media_galleries/picasa_album_table_reader.h" 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <algorithm> 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <string> 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/path_service.h" 11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/string_util.h" 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/utf_string_conversions.h" 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/common/media_galleries/pmp_constants.h" 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/utility/media_galleries/pmp_column_reader.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace picasa { 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace { 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// |variant_time| is specified as the number of days from Dec 30, 1899. 21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbase::Time TimeFromMicrosoftVariantTime(double variant_time) { 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::TimeDelta variant_delta = base::TimeDelta::FromMicroseconds( 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch static_cast<int64>(variant_time * base::Time::kMicrosecondsPerDay)); 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return base::Time::FromLocalExploded(kPmpVariantTimeEpoch) + variant_delta; 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochPicasaAlbumTableReader::PicasaAlbumTableReader(AlbumTableFiles table_files) 31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch : table_files_(table_files.Pass()), 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch initialized_(false) { 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)PicasaAlbumTableReader::~PicasaAlbumTableReader() { 361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst std::vector<AlbumInfo>& PicasaAlbumTableReader::folders() const { 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(initialized_); 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return folders_; 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst std::vector<AlbumInfo>& PicasaAlbumTableReader::albums() const { 44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(initialized_); 45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return albums_; 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool PicasaAlbumTableReader::Init() { 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (initialized_) 50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 52c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!table_files_.indicator_file.IsValid()) 53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PmpColumnReader category_column, date_column, filename_column, name_column, 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch token_column, uid_column; 57c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!category_column.ReadFile(&table_files_.category_file, PMP_TYPE_UINT32) || 58c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch !date_column.ReadFile(&table_files_.date_file, PMP_TYPE_DOUBLE64) || 59c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch !filename_column.ReadFile(&table_files_.filename_file, PMP_TYPE_STRING) || 60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch !name_column.ReadFile(&table_files_.name_file, PMP_TYPE_STRING) || 61c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch !token_column.ReadFile(&table_files_.token_file, PMP_TYPE_STRING) || 62c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch !uid_column.ReadFile(&table_files_.uid_file, PMP_TYPE_STRING)) { 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // In the PMP format, columns can be different lengths. The number of rows 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // in the table is max of all the columns, and short columns are NULL padded. 68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32 row_count = 0; 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch row_count = std::max(row_count, category_column.rows_read()); 70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch row_count = std::max(row_count, date_column.rows_read()); 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch row_count = std::max(row_count, filename_column.rows_read()); 72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch row_count = std::max(row_count, name_column.rows_read()); 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch row_count = std::max(row_count, token_column.rows_read()); 74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch row_count = std::max(row_count, uid_column.rows_read()); 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (uint32 i = 0; i < row_count; i++) { 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32 category = kAlbumCategoryInvalid; 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch double date = 0; 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string name; 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string uid; 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // PMP tables often contain 'garbage' rows of deleted or auto-generated 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // album-like entities. We ignore those rows. 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!category_column.ReadUInt32(i, &category) || 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch !date_column.ReadDouble64(i, &date) || 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch !name_column.ReadString(i, &name) || name.empty() || 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch !uid_column.ReadString(i, &uid) || uid.empty()) { 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch continue; 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Time timestamp = TimeFromMicrosoftVariantTime(date); 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (category == kAlbumCategoryAlbum) { 9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::string token; 9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!token_column.ReadString(i, &token) || token.empty() || 9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) !StartsWithASCII(token, kAlbumTokenPrefix, false)) { 9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) continue; 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) albums_.push_back(AlbumInfo(name, timestamp, uid, base::FilePath())); 10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (category == kAlbumCategoryFolder) { 10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::string filename; 10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!filename_column.ReadString(i, &filename) || filename.empty()) 10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) continue; 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::FilePath path = 10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::FilePath(base::FilePath::FromUTF8Unsafe(filename)); 10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) folders_.push_back(AlbumInfo(name, timestamp, uid, path)); 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch initialized_ = true; 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace picasa 117