Home | History | Annotate | Download | only in media_galleries
      1 // Copyright 2013 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/media_galleries/picasa_album_table_reader.h"
      6 
      7 #include <algorithm>
      8 #include <string>
      9 
     10 #include "base/path_service.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "chrome/common/media_galleries/pmp_constants.h"
     14 #include "chrome/utility/media_galleries/pmp_column_reader.h"
     15 
     16 namespace picasa {
     17 
     18 namespace {
     19 
     20 // |variant_time| is specified as the number of days from Dec 30, 1899.
     21 base::Time TimeFromMicrosoftVariantTime(double variant_time) {
     22   base::TimeDelta variant_delta = base::TimeDelta::FromMicroseconds(
     23       static_cast<int64>(variant_time * base::Time::kMicrosecondsPerDay));
     24 
     25   return base::Time::FromLocalExploded(kPmpVariantTimeEpoch) + variant_delta;
     26 }
     27 
     28 }  // namespace
     29 
     30 PicasaAlbumTableReader::PicasaAlbumTableReader(AlbumTableFiles table_files)
     31     : table_files_(table_files.Pass()),
     32       initialized_(false) {
     33 }
     34 
     35 PicasaAlbumTableReader::~PicasaAlbumTableReader() {
     36 }
     37 
     38 const std::vector<AlbumInfo>& PicasaAlbumTableReader::folders() const {
     39   DCHECK(initialized_);
     40   return folders_;
     41 }
     42 
     43 const std::vector<AlbumInfo>& PicasaAlbumTableReader::albums() const {
     44   DCHECK(initialized_);
     45   return albums_;
     46 }
     47 
     48 bool PicasaAlbumTableReader::Init() {
     49   if (initialized_)
     50     return true;
     51 
     52   if (!table_files_.indicator_file.IsValid())
     53     return false;
     54 
     55   PmpColumnReader category_column, date_column, filename_column, name_column,
     56                   token_column, uid_column;
     57   if (!category_column.ReadFile(&table_files_.category_file, PMP_TYPE_UINT32) ||
     58       !date_column.ReadFile(&table_files_.date_file, PMP_TYPE_DOUBLE64) ||
     59       !filename_column.ReadFile(&table_files_.filename_file, PMP_TYPE_STRING) ||
     60       !name_column.ReadFile(&table_files_.name_file, PMP_TYPE_STRING) ||
     61       !token_column.ReadFile(&table_files_.token_file, PMP_TYPE_STRING) ||
     62       !uid_column.ReadFile(&table_files_.uid_file, PMP_TYPE_STRING)) {
     63     return false;
     64   }
     65 
     66   // In the PMP format, columns can be different lengths. The number of rows
     67   // in the table is max of all the columns, and short columns are NULL padded.
     68   uint32 row_count = 0;
     69   row_count = std::max(row_count, category_column.rows_read());
     70   row_count = std::max(row_count, date_column.rows_read());
     71   row_count = std::max(row_count, filename_column.rows_read());
     72   row_count = std::max(row_count, name_column.rows_read());
     73   row_count = std::max(row_count, token_column.rows_read());
     74   row_count = std::max(row_count, uid_column.rows_read());
     75 
     76   for (uint32 i = 0; i < row_count; i++) {
     77     uint32 category = kAlbumCategoryInvalid;
     78     double date = 0;
     79     std::string name;
     80     std::string uid;
     81     // PMP tables often contain 'garbage' rows of deleted or auto-generated
     82     // album-like entities. We ignore those rows.
     83     if (!category_column.ReadUInt32(i, &category) ||
     84         !date_column.ReadDouble64(i, &date) ||
     85         !name_column.ReadString(i, &name) || name.empty() ||
     86         !uid_column.ReadString(i, &uid) || uid.empty()) {
     87       continue;
     88     }
     89 
     90     base::Time timestamp = TimeFromMicrosoftVariantTime(date);
     91 
     92     if (category == kAlbumCategoryAlbum) {
     93       std::string token;
     94       if (!token_column.ReadString(i, &token) || token.empty() ||
     95           !StartsWithASCII(token, kAlbumTokenPrefix, false)) {
     96         continue;
     97       }
     98 
     99       albums_.push_back(AlbumInfo(name, timestamp, uid, base::FilePath()));
    100     } else if (category == kAlbumCategoryFolder) {
    101       std::string filename;
    102       if (!filename_column.ReadString(i, &filename) || filename.empty())
    103         continue;
    104 
    105       base::FilePath path =
    106           base::FilePath(base::FilePath::FromUTF8Unsafe(filename));
    107 
    108       folders_.push_back(AlbumInfo(name, timestamp, uid, path));
    109     }
    110   }
    111 
    112   initialized_ = true;
    113   return true;
    114 }
    115 
    116 }  // namespace picasa
    117