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