<commit_before>/////////////////////////////////////////////////////////////////////////////
//  This file is part of the hdf5 data handler for the OPeNDAP data server.
//
// Author:   Hyo-Kyung Lee <hyoklee@hdfgroup.org>
// Copyright (c) 2007 The HDF Group
//
/////////////////////////////////////////////////////////////////////////////
// #define DODS_DEBUG
#include <iostream>
#include <iomanip>
#include <debug.h>
#include <util.h>
#include <cmath>

#include "H5EOS.h"

using namespace std;

int hdfeoslex();
int hdfeosparse(void *arg);
struct yy_buffer_state;
yy_buffer_state *hdfeos_scan_string(const char *str);
extern bool valid_projection;
extern bool grid_structure_found;
H5EOS::H5EOS()
{
  TES = false;
  valid = false;
  point_lower = 0.0f;
  point_upper = 0.0f;
  point_left = 0.0f;
  point_right = 0.0f;
  gradient_x = 0.0f;
  gradient_y = 0.0f;
  dimension_data = NULL;
  bmetadata_Struct = false;
#ifdef NASA_EOS_META
  bmetadata_Archived = false;
  bmetadata_Core = false;
  bmetadata_core = false;
  bmetadata_product = false;
  bmetadata_subset = false;
#endif

}

H5EOS::~H5EOS()
{
}

bool H5EOS::has_group(hid_t id, const char *name)
{
  hid_t hid;
  H5E_BEGIN_TRY {
    hid = H5Gopen(id, name);
  } H5E_END_TRY;
  if (hid < 0) {
    return false;
  } else {
    return true;
  }

}

bool H5EOS::has_dataset(hid_t id, const char *name)
{
  hid_t hid;
  H5E_BEGIN_TRY {
    hid = H5Dopen(id, name);
  } H5E_END_TRY;              // <hyokyung 2007.06.20. 10:25:25>
  if (hid < 0) {
    return false;
  } else {
    return true;
  }
}

void H5EOS::add_data_path(string full_path)
{
#ifdef CF
  string short_path = generate_short_name(full_path);
  DBG(cerr << "Short path is:" << short_path << endl);
  long_to_short[full_path] = short_path;
#endif

  DBG(cerr << "Full path is:" << full_path << endl);
  full_data_paths.push_back(full_path);
}

void H5EOS::add_dimension_list(string full_path, string dimension_list)
{
  full_data_path_to_dimension_list_map[full_path] = dimension_list;
  DBG(cerr << "Dimension List is:" <<
      full_data_path_to_dimension_list_map[full_path] << endl);
}

void H5EOS::add_dimension_map(string dimension_name, int dimension)
{
  bool has_dimension = false;
#ifdef CF
  dimension_name = cut_long_name(dimension_name);
#endif

  int i;
  for (i = 0; i < (int) dimensions.size(); i++) {
    std::string str = dimensions.at(i);
    if (str == dimension_name) {
      has_dimension = true;
      break;
    }
  }

  if (!has_dimension) {
    dimensions.push_back(dimension_name);
    dimension_map[dimension_name] = dimension;
  }
}

bool H5EOS::check_eos(hid_t id)
{

  reset();

  // Check if this file has the group called "HDFEOS INFORMATION".
  if (has_group(id, "HDFEOS INFORMATION")) {

    if (set_metadata(id, "StructMetadata", metadata_Struct)) {
      valid = true;
    } else {
      valid = false;
    }

    if (valid) {
      hdfeos_scan_string(metadata_Struct);
      hdfeosparse(this);
#ifdef NASA_EOS_META
      set_metadata(id, "coremetadata", metadata_core);
      // cerr << metadata_core << endl;
      if(string(metadata_core).find("\"TES\"") != string::npos){
	TES = true;
      }

      set_metadata(id, "CoreMetadata", metadata_Core);
      set_metadata(id, "ArchivedMetadata", metadata_Archived);
      set_metadata(id, "subsetmetadata", metadata_subset);
      set_metadata(id, "productmetadata", metadata_product);
#endif
    }

    return valid;
  }
  return false;
}

void H5EOS::get_dimensions(string name, vector < string > &tokens)
{
  string str = full_data_path_to_dimension_list_map[name];
  // Skip delimiters at beginning.
  string::size_type lastPos = str.find_first_not_of(',', 0);
  // Find first "non-delimiter".
  string::size_type pos = str.find_first_of(',', lastPos);

  while (string::npos != pos || string::npos != lastPos) {
    // Found a token, add it to the vector.
    tokens.push_back(str.substr(lastPos, pos - lastPos));
    // Skip delimiters.  Note the "not_of"
    lastPos = str.find_first_not_of(',', pos);
    // Find next "non-delimiter"
    pos = str.find_first_of(',', lastPos);
  }
}

///////////////////////////////////////////////////////////////////////////////
/// Retrieve the dimension list from the argument "name" grid and tokenize the list into the string vector.
///////////////////////////////////////////////////////////////////////////////
int H5EOS::get_dimension_size(string name)
{
  return dimension_map[name];
}

bool H5EOS::is_grid(string name)
{
  int i;
  for (i = 0; i < (int) full_data_paths.size(); i++) {
    std::string str = full_data_paths.at(i);
    if (str == name) {
      return true;
    }
  }
  return false;
}

bool H5EOS::is_TES()
{
  return TES;
}

bool H5EOS::is_valid()
{
  return valid;
}

void H5EOS::print()
{

  cout << "Left = " << point_left << endl;
  cout << "Right = " << point_right << endl;
  cout << "Lower = " << point_lower << endl;
  cout << "Upper = " << point_upper << endl;

  cout << "Total number of paths = " << full_data_paths.size() << endl;
  for (int i = 0; i < (int) full_data_paths.size(); i++) {
    cout << "Element " << full_data_paths.at(i) << endl;
  }
}

bool H5EOS::set_dimension_array()
{
  int i = 0;
  int j = 0;
  int size = dimensions.size();

  dods_float32 *convbuf = NULL;

  if (libdap::size_ok(sizeof(dods_float32), size))
    dimension_data = new dods_float32*[size];
  else
    throw InternalErr(__FILE__, __LINE__,
		      "Unable to allocate memory.");
  DBG(cerr << ">set_dimension_array():Dimensions size = " << size <<
      endl);
  for (j = 0; j < (int) dimensions.size(); j++) {
    string dim_name = dimensions.at(j);
    int dim_size = dimension_map[dim_name];

    DBG(cerr << "=set_dimension_array():Dim name = " << dim_name <<
	std::endl);
    DBG(cerr << "=set_dimension_array():Dim size = " << dim_size <<
	std::endl);

    if (dim_size > 0) {
      if (libdap::size_ok(sizeof(dods_float32), dim_size))
	convbuf = new dods_float32[dim_size];
      else
	throw InternalErr(__FILE__, __LINE__,
			  "Unable to allocate memory.");

      if ((dim_name.find("XDim", (int) dim_name.size() - 4)) !=
	  string::npos) {
	gradient_x =
	  (point_right - point_left) / (float) (dim_size);
	for (i = 0; i < dim_size; i++) {
	  if(!TES){
	    convbuf[i] = (dods_float32)
	      (point_left + (float) i * gradient_x + (gradient_x / 2.0)) / 1000000.0;
	  }
	  else{
	    convbuf[i] = (dods_float32)
	      (point_left + (float) i * gradient_x) / 1000000.0;
	  }
	}
      } else if ((dim_name.find("YDim", (int) dim_name.size() - 4))
		 != string::npos) {

	if(TES){
	  // swap the upper and lower points for TES products
	  float temp = point_upper;
	  point_upper = point_lower;
	  point_lower = temp;
	}

	gradient_y =
	  (point_upper - point_lower) / (float) (dim_size);
	for (i = 0; i < dim_size; i++) {
	  if(!TES){
	    convbuf[i] = (dods_float32)
	      (point_lower + (float) i * gradient_y + (gradient_y / 2.0)) / 1000000.0;
	  }
	  else{
	    gradient_y = ceilf(gradient_y/1000000.0f) * 1000000.0f;
	    convbuf[i] = (dods_float32)
	      (point_lower + (float) i * gradient_y) / 1000000.0;
	  }
	}
      } else {
	for (i = 0; i < dim_size; i++) {
	  convbuf[i] = (dods_float32) i;      // meaningless number.
	}
      }
    }                       // if dim_size > 0
    else {
      DBG(cerr << "Negative dimension " << endl);
      return false;
    }
    dimension_data[j] = convbuf;
  }                           // for
  DBG(cerr << "<set_dimension_array()" << endl);
  return true;
}

string H5EOS::get_grid_name(string full_path)
{
  int end = full_path.find("/", 14);
  return full_path.substr(0, end + 1);        // Include the last "/".
}

int H5EOS::get_dimension_data_location(string dimension_name)
{
  int j;
  for (j = 0; j < (int) dimensions.size(); j++) {
    string dim_name = dimensions.at(j);
    if (dim_name == dimension_name)
      return j;
  }
  return -1;
}

bool H5EOS::set_metadata(hid_t id, char *metadata_name, char *chr_all)
{
  bool valid = false;
  int i = -1;

  for (i = -1; i < 10; i++) { // Assume that 10 is reasonable count of StructMetadata files
    // Check if this file has the dataset called "StructMetadata".
    // Open the dataset.
    char dname[255];

    if (i == -1) {
      snprintf(dname, 255, "/HDFEOS INFORMATION/%s", metadata_name);
    } else {
      snprintf(dname, 255, "/HDFEOS INFORMATION/%s.%d",
	       metadata_name, i);
    }

    DBG(cerr << "Checking Dataset " << dname << endl);

    if (has_dataset(id, dname)) {
      hid_t dset = H5Dopen(id, dname);
      hid_t datatype, dataspace;

      if ((datatype = H5Dget_type(dset)) < 0) {
	cerr << "H5EOS.cc failed to obtain datatype from  dataset "
	     << dset << endl;
	break;
      }
      if ((dataspace = H5Dget_space(dset)) < 0) {
	cerr <<
	  "H5EOS.cc failed to obtain dataspace from  dataset " <<
	  dset << endl;
	break;
      }
      size_t size = H5Tget_size(datatype);
      char *chr = new char[size + 1];
      H5Dread(dset, datatype, dataspace, dataspace, H5P_DEFAULT,
	      (void *) chr);
      strcat(chr_all, chr);
      valid = true;
      delete[] chr;
    } else {
      // The sequence can skip <metdata>.0.
      // Forexample, "coremetadata" and then "coremetadata.1".
      if (i > 2)
	break;
    }
  }

  return valid;

}

void H5EOS::reset()
{
  int j;
  grid_structure_found = false;
  valid_projection = false;
  valid = false;
  point_lower = 0.0;
  point_upper = 0.0;
  point_left = 0.0;
  point_right = 0.0;
  gradient_x = 0.0;
  gradient_y = 0.0;
  bmetadata_Struct = false;
#ifdef NASA_EOS_META
  bmetadata_Archived = false;
  bmetadata_Core = false;
  bmetadata_core = false;
  bmetadata_product = false;
  bmetadata_subset = false;
#endif

  if(dimension_data != NULL){
    for (j = 0; j < (int) dimensions.size(); j++) {
      if(dimension_data[j] != NULL)
	delete dimension_data[j];
    }
    delete dimension_data;
    dimension_data = NULL;
  }

  if(!dimension_map.empty()){
    dimension_map.clear();
  }
  if(!full_data_path_to_dimension_list_map.empty()){
    full_data_path_to_dimension_list_map.clear();
  }

  if(!dimensions.empty()){
    dimensions.clear();
  }
  if(!full_data_paths.empty()){
    full_data_paths.clear();
  }
  // Clear the contents of the metadata string buffer.
  strcpy(metadata_Struct, "");
  strcpy(metadata_Archived, "");
  strcpy(metadata_Core, "");
  strcpy(metadata_core, "");
  strcpy(metadata_product, "");
  strcpy(metadata_subset, "");
  H5CF::reset();
}

void H5EOS::get_all_dimensions(vector < string > &tokens)
{
  int j;
  for (j = 0; j < (int) dimensions.size(); j++) {
    string dim_name = dimensions.at(j);
    tokens.push_back(dim_name);
    DBG(cerr << "=get_all_dimensions():Dim name = " << dim_name <<
	std::endl);
  }
}

<commit_msg>Added TES = false inside H5EOS::reset().<commit_after>/////////////////////////////////////////////////////////////////////////////
//  This file is part of the hdf5 data handler for the OPeNDAP data server.
//
// Author:   Hyo-Kyung Lee <hyoklee@hdfgroup.org>
// Copyright (c) 2007 The HDF Group
//
/////////////////////////////////////////////////////////////////////////////
// #define DODS_DEBUG
#include <iostream>
#include <iomanip>
#include <debug.h>
#include <util.h>
#include <cmath>

#include "H5EOS.h"

using namespace std;

int hdfeoslex();
int hdfeosparse(void *arg);
struct yy_buffer_state;
yy_buffer_state *hdfeos_scan_string(const char *str);
extern bool valid_projection;
extern bool grid_structure_found;
H5EOS::H5EOS()
{
  TES = false;
  valid = false;
  point_lower = 0.0f;
  point_upper = 0.0f;
  point_left = 0.0f;
  point_right = 0.0f;
  gradient_x = 0.0f;
  gradient_y = 0.0f;
  dimension_data = NULL;
  bmetadata_Struct = false;
#ifdef NASA_EOS_META
  bmetadata_Archived = false;
  bmetadata_Core = false;
  bmetadata_core = false;
  bmetadata_product = false;
  bmetadata_subset = false;
#endif

}

H5EOS::~H5EOS()
{
}

bool H5EOS::has_group(hid_t id, const char *name)
{
  hid_t hid;
  H5E_BEGIN_TRY {
    hid = H5Gopen(id, name);
  } H5E_END_TRY;
  if (hid < 0) {
    return false;
  } else {
    return true;
  }

}

bool H5EOS::has_dataset(hid_t id, const char *name)
{
  hid_t hid;
  H5E_BEGIN_TRY {
    hid = H5Dopen(id, name);
  } H5E_END_TRY;              // <hyokyung 2007.06.20. 10:25:25>
  if (hid < 0) {
    return false;
  } else {
    return true;
  }
}

void H5EOS::add_data_path(string full_path)
{
#ifdef CF
  string short_path = generate_short_name(full_path);
  DBG(cerr << "Short path is:" << short_path << endl);
  long_to_short[full_path] = short_path;
#endif

  DBG(cerr << "Full path is:" << full_path << endl);
  full_data_paths.push_back(full_path);
}

void H5EOS::add_dimension_list(string full_path, string dimension_list)
{
  full_data_path_to_dimension_list_map[full_path] = dimension_list;
  DBG(cerr << "Dimension List is:" <<
      full_data_path_to_dimension_list_map[full_path] << endl);
}

void H5EOS::add_dimension_map(string dimension_name, int dimension)
{
  bool has_dimension = false;
#ifdef CF
  dimension_name = cut_long_name(dimension_name);
#endif

  int i;
  for (i = 0; i < (int) dimensions.size(); i++) {
    std::string str = dimensions.at(i);
    if (str == dimension_name) {
      has_dimension = true;
      break;
    }
  }

  if (!has_dimension) {
    dimensions.push_back(dimension_name);
    dimension_map[dimension_name] = dimension;
  }
}

bool H5EOS::check_eos(hid_t id)
{

  reset();

  // Check if this file has the group called "HDFEOS INFORMATION".
  if (has_group(id, "HDFEOS INFORMATION")) {

    if (set_metadata(id, "StructMetadata", metadata_Struct)) {
      valid = true;
    } else {
      valid = false;
    }

    if (valid) {
      hdfeos_scan_string(metadata_Struct);
      hdfeosparse(this);
#ifdef NASA_EOS_META
      set_metadata(id, "coremetadata", metadata_core);
      // cerr << metadata_core << endl;
      if(string(metadata_core).find("\"TES\"") != string::npos){
	TES = true;
      }

      set_metadata(id, "CoreMetadata", metadata_Core);
      set_metadata(id, "ArchivedMetadata", metadata_Archived);
      set_metadata(id, "subsetmetadata", metadata_subset);
      set_metadata(id, "productmetadata", metadata_product);
#endif
    }

    return valid;
  }
  return false;
}

void H5EOS::get_dimensions(string name, vector < string > &tokens)
{
  string str = full_data_path_to_dimension_list_map[name];
  // Skip delimiters at beginning.
  string::size_type lastPos = str.find_first_not_of(',', 0);
  // Find first "non-delimiter".
  string::size_type pos = str.find_first_of(',', lastPos);

  while (string::npos != pos || string::npos != lastPos) {
    // Found a token, add it to the vector.
    tokens.push_back(str.substr(lastPos, pos - lastPos));
    // Skip delimiters.  Note the "not_of"
    lastPos = str.find_first_not_of(',', pos);
    // Find next "non-delimiter"
    pos = str.find_first_of(',', lastPos);
  }
}

///////////////////////////////////////////////////////////////////////////////
/// Retrieve the dimension list from the argument "name" grid and tokenize the list into the string vector.
///////////////////////////////////////////////////////////////////////////////
int H5EOS::get_dimension_size(string name)
{
  return dimension_map[name];
}

bool H5EOS::is_grid(string name)
{
  int i;
  for (i = 0; i < (int) full_data_paths.size(); i++) {
    std::string str = full_data_paths.at(i);
    if (str == name) {
      return true;
    }
  }
  return false;
}

bool H5EOS::is_TES()
{
  return TES;
}

bool H5EOS::is_valid()
{
  return valid;
}

void H5EOS::print()
{

  cout << "Left = " << point_left << endl;
  cout << "Right = " << point_right << endl;
  cout << "Lower = " << point_lower << endl;
  cout << "Upper = " << point_upper << endl;

  cout << "Total number of paths = " << full_data_paths.size() << endl;
  for (int i = 0; i < (int) full_data_paths.size(); i++) {
    cout << "Element " << full_data_paths.at(i) << endl;
  }
}

bool H5EOS::set_dimension_array()
{
  int i = 0;
  int j = 0;
  int size = dimensions.size();

  dods_float32 *convbuf = NULL;

  if (libdap::size_ok(sizeof(dods_float32), size))
    dimension_data = new dods_float32*[size];
  else
    throw InternalErr(__FILE__, __LINE__,
		      "Unable to allocate memory.");
  DBG(cerr << ">set_dimension_array():Dimensions size = " << size <<
      endl);
  for (j = 0; j < (int) dimensions.size(); j++) {
    string dim_name = dimensions.at(j);
    int dim_size = dimension_map[dim_name];

    DBG(cerr << "=set_dimension_array():Dim name = " << dim_name <<
	std::endl);
    DBG(cerr << "=set_dimension_array():Dim size = " << dim_size <<
	std::endl);

    if (dim_size > 0) {
      if (libdap::size_ok(sizeof(dods_float32), dim_size))
	convbuf = new dods_float32[dim_size];
      else
	throw InternalErr(__FILE__, __LINE__,
			  "Unable to allocate memory.");

      if ((dim_name.find("XDim", (int) dim_name.size() - 4)) !=
	  string::npos) {
	gradient_x =
	  (point_right - point_left) / (float) (dim_size);
	for (i = 0; i < dim_size; i++) {
	  if(!TES){
	    convbuf[i] = (dods_float32)
	      (point_left + (float) i * gradient_x + (gradient_x / 2.0)) / 1000000.0;
	  }
	  else{
	    convbuf[i] = (dods_float32)
	      (point_left + (float) i * gradient_x) / 1000000.0;
	  }
	}
      } else if ((dim_name.find("YDim", (int) dim_name.size() - 4))
		 != string::npos) {

	if(TES){
	  // swap the upper and lower points for TES products
	  float temp = point_upper;
	  point_upper = point_lower;
	  point_lower = temp;
	}

	gradient_y =
	  (point_upper - point_lower) / (float) (dim_size);
	for (i = 0; i < dim_size; i++) {
	  if(!TES){
	    convbuf[i] = (dods_float32)
	      (point_lower + (float) i * gradient_y + (gradient_y / 2.0)) / 1000000.0;
	  }
	  else{
	    gradient_y = ceilf(gradient_y/1000000.0f) * 1000000.0f;
	    convbuf[i] = (dods_float32)
	      (point_lower + (float) i * gradient_y) / 1000000.0;
	  }
	}
      } else {
	for (i = 0; i < dim_size; i++) {
	  convbuf[i] = (dods_float32) i;      // meaningless number.
	}
      }
    }                       // if dim_size > 0
    else {
      DBG(cerr << "Negative dimension " << endl);
      return false;
    }
    dimension_data[j] = convbuf;
  }                           // for
  DBG(cerr << "<set_dimension_array()" << endl);
  return true;
}

string H5EOS::get_grid_name(string full_path)
{
  int end = full_path.find("/", 14);
  return full_path.substr(0, end + 1);        // Include the last "/".
}

int H5EOS::get_dimension_data_location(string dimension_name)
{
  int j;
  for (j = 0; j < (int) dimensions.size(); j++) {
    string dim_name = dimensions.at(j);
    if (dim_name == dimension_name)
      return j;
  }
  return -1;
}

bool H5EOS::set_metadata(hid_t id, char *metadata_name, char *chr_all)
{
  bool valid = false;
  int i = -1;

  for (i = -1; i < 10; i++) { // Assume that 10 is reasonable count of StructMetadata files
    // Check if this file has the dataset called "StructMetadata".
    // Open the dataset.
    char dname[255];

    if (i == -1) {
      snprintf(dname, 255, "/HDFEOS INFORMATION/%s", metadata_name);
    } else {
      snprintf(dname, 255, "/HDFEOS INFORMATION/%s.%d",
	       metadata_name, i);
    }

    DBG(cerr << "Checking Dataset " << dname << endl);

    if (has_dataset(id, dname)) {
      hid_t dset = H5Dopen(id, dname);
      hid_t datatype, dataspace;

      if ((datatype = H5Dget_type(dset)) < 0) {
	cerr << "H5EOS.cc failed to obtain datatype from  dataset "
	     << dset << endl;
	break;
      }
      if ((dataspace = H5Dget_space(dset)) < 0) {
	cerr <<
	  "H5EOS.cc failed to obtain dataspace from  dataset " <<
	  dset << endl;
	break;
      }
      size_t size = H5Tget_size(datatype);
      char *chr = new char[size + 1];
      H5Dread(dset, datatype, dataspace, dataspace, H5P_DEFAULT,
	      (void *) chr);
      strcat(chr_all, chr);
      valid = true;
      delete[] chr;
    } else {
      // The sequence can skip <metdata>.0.
      // Forexample, "coremetadata" and then "coremetadata.1".
      if (i > 2)
	break;
    }
  }

  return valid;

}

void H5EOS::reset()
{
  int j;
  grid_structure_found = false;
  valid_projection = false;
  valid = false;
  TES = false;
  point_lower = 0.0;
  point_upper = 0.0;
  point_left = 0.0;
  point_right = 0.0;
  gradient_x = 0.0;
  gradient_y = 0.0;
  bmetadata_Struct = false;
#ifdef NASA_EOS_META
  bmetadata_Archived = false;
  bmetadata_Core = false;
  bmetadata_core = false;
  bmetadata_product = false;
  bmetadata_subset = false;
#endif

  if(dimension_data != NULL){
    for (j = 0; j < (int) dimensions.size(); j++) {
      if(dimension_data[j] != NULL)
	delete dimension_data[j];
    }
    delete dimension_data;
    dimension_data = NULL;
  }

  if(!dimension_map.empty()){
    dimension_map.clear();
  }
  if(!full_data_path_to_dimension_list_map.empty()){
    full_data_path_to_dimension_list_map.clear();
  }

  if(!dimensions.empty()){
    dimensions.clear();
  }
  if(!full_data_paths.empty()){
    full_data_paths.clear();
  }
  // Clear the contents of the metadata string buffer.
  strcpy(metadata_Struct, "");
  strcpy(metadata_Archived, "");
  strcpy(metadata_Core, "");
  strcpy(metadata_core, "");
  strcpy(metadata_product, "");
  strcpy(metadata_subset, "");
  H5CF::reset();
}

void H5EOS::get_all_dimensions(vector < string > &tokens)
{
  int j;
  for (j = 0; j < (int) dimensions.size(); j++) {
    string dim_name = dimensions.at(j);
    tokens.push_back(dim_name);
    DBG(cerr << "=get_all_dimensions():Dim name = " << dim_name <<
	std::endl);
  }
}

<|endoftext|>


<commit_before>//   Copyright 2016-2017 Jean-Francois Poilpret
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

/*
 * Hardware UART example.
 * This program demonstrates usage of FastArduino Hardware UART support (on target supporting it) and formatted
 * input streams.
 *
 * Wiring:
 * - on Arduino UNO, Arduino NANO and Arduino MEGA:
 *   - Use standard TX/RX
 * - on ATmega328P based boards:
 *   - Use standard TX/RX connected to an Serial-USB converter
 * - on ATtinyX4 based boards:
 *   - NOT SUPPORTED
 */

#include <fastarduino/time.h>
#include <fastarduino/uart.h>

// Define vectors we need in the example
REGISTER_UART_ISR(0)

// Buffers for UART
static const uint8_t INPUT_BUFFER_SIZE = 64;
static const uint8_t OUTPUT_BUFFER_SIZE = 64;
static char input_buffer[INPUT_BUFFER_SIZE];
static char output_buffer[OUTPUT_BUFFER_SIZE];

using namespace streams;

using INPUT = FormattedInput<InputBuffer>;
using OUTPUT = FormattedOutput<OutputBuffer>;

template<typename T>
static void handle(OUTPUT& out, INPUT& in, const flash::FlashStorage* type)
{
	out << type << F(": ") << flush;
	T value{};
	in >> skipws >> value;
	out << value << endl;
}

template<typename T>
static void display_num(OUTPUT& out, T value)
{
	out << bin << value << endl;
	out << dec << value << endl;
	out << oct << value << endl;
	out << hex << value << endl;
}

template<typename T>
static void handle_num(OUTPUT& out, T value, const flash::FlashStorage* type)
{
	out << F("testing output of ") << type << F(" (") << dec << value << ')' << endl;
	display_num<T>(out, value);

	out << showbase;
	display_num<T>(out, value);
	out << noshowbase;

	out << uppercase;
	display_num<T>(out, value);
	out << nouppercase;

	out << uppercase << showbase;
	display_num<T>(out, value);
	out << nouppercase << noshowbase;

	out << showpos;
	display_num<T>(out, value);
	out << noshowpos;
}

int main() __attribute__((OS_main));
int main()
{
	// Enable interrupts at startup time
	sei();

	// Start UART
	serial::hard::UART<board::USART::USART0> uart{input_buffer, output_buffer};
	uart.register_handler();
	uart.begin(115200);
	INPUT in = uart.fin();
	OUTPUT out = uart.fout();

	// Check all output manipulators
	handle_num<uint16_t>(out, 1234, F("uint16_t"));
	handle_num<int16_t>(out, 1234, F("int16_t"));
	handle_num<int16_t>(out, -1234, F("int16_t"));

	handle_num<uint32_t>(out, 123456, F("uint32_t"));
	handle_num<int32_t>(out, 123456, F("int32_t"));
	handle_num<int32_t>(out, -123456, F("int32_t"));

	//TODO check floats
	//TODO check other types

	//TODO check justification: setw(), setfill(), left, right...

	// Event Loop
	while (true)
	{
		handle<char>(out, in, F("char"));
		handle<uint16_t>(out, in, F("uint16_t"));
		handle<int16_t>(out, in, F("int16_t"));
		handle<uint32_t>(out, in, F("uint32_t"));
		handle<int32_t>(out, in, F("int32_t"));
		handle<bool>(out, in, F("bool"));

		time::delay_ms(1000);
	}
}
<commit_msg>Stream refactoring: add float test cases to example.<commit_after>//   Copyright 2016-2017 Jean-Francois Poilpret
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

/*
 * Hardware UART example.
 * This program demonstrates usage of FastArduino Hardware UART support (on target supporting it) and formatted
 * input streams.
 *
 * Wiring:
 * - on Arduino UNO, Arduino NANO and Arduino MEGA:
 *   - Use standard TX/RX
 * - on ATmega328P based boards:
 *   - Use standard TX/RX connected to an Serial-USB converter
 * - on ATtinyX4 based boards:
 *   - NOT SUPPORTED
 */

#include <fastarduino/time.h>
#include <fastarduino/uart.h>

// Define vectors we need in the example
REGISTER_UART_ISR(0)

// Buffers for UART
static const uint8_t INPUT_BUFFER_SIZE = 64;
static const uint8_t OUTPUT_BUFFER_SIZE = 64;
static char input_buffer[INPUT_BUFFER_SIZE];
static char output_buffer[OUTPUT_BUFFER_SIZE];

using namespace streams;

using INPUT = FormattedInput<InputBuffer>;
using OUTPUT = FormattedOutput<OutputBuffer>;

template<typename T>
static void handle(OUTPUT& out, INPUT& in, const flash::FlashStorage* type)
{
	out << type << F(": ") << flush;
	T value{};
	in >> skipws >> value;
	out << value << endl;
}

template<typename T>
static void display_num(OUTPUT& out, T value)
{
	out << bin << value << endl;
	out << dec << value << endl;
	out << oct << value << endl;
	out << hex << value << endl;
}

template<typename T>
static void handle_num(OUTPUT& out, T value, const flash::FlashStorage* type)
{
	out << F("testing output of ") << type << F(" (") << dec << value << ')' << endl;
	display_num<T>(out, value);

	out << showbase;
	display_num<T>(out, value);
	out << noshowbase;

	out << uppercase;
	display_num<T>(out, value);
	out << nouppercase;

	out << uppercase << showbase;
	display_num<T>(out, value);
	out << nouppercase << noshowbase;

	out << showpos;
	display_num<T>(out, value);
	out << noshowpos;
}

static void handle_float(OUTPUT& out, double value)
{
	out << F("testing output of double (") << defaultfloat << value << ')' << endl;
	display_num<double>(out, value);

	out << showbase;
	display_num<double>(out, value);
	out << noshowbase;

	out << defaultfloat << value << endl;
	out << fixed << value << endl;
	out << scientific << value << endl;

	out << uppercase;
	out << defaultfloat << value << endl;
	out << fixed << value << endl;
	out << scientific << value << endl;
	out << nouppercase;

	out << showpos;
	out << defaultfloat << value << endl;
	out << fixed << value << endl;
	out << scientific << value << endl;
	out << noshowpos;

	//TODO check precision too
}

int main() __attribute__((OS_main));
int main()
{
	// Enable interrupts at startup time
	sei();

	// Start UART
	serial::hard::UART<board::USART::USART0> uart{input_buffer, output_buffer};
	uart.register_handler();
	uart.begin(115200);
	INPUT in = uart.fin();
	OUTPUT out = uart.fout();

	// Check all output manipulators
	handle_num<uint16_t>(out, 1234, F("uint16_t"));
	handle_num<int16_t>(out, 1234, F("int16_t"));
	handle_num<int16_t>(out, -1234, F("int16_t"));

	handle_num<uint32_t>(out, 123456, F("uint32_t"));
	handle_num<int32_t>(out, 123456, F("int32_t"));
	handle_num<int32_t>(out, -123456, F("int32_t"));

	// check floats
	handle_float(out, 123.456);
	handle_float(out, -123.456);
	handle_float(out, -12345678901234567890.12345);

	//TODO check other types

	//TODO check justification: setw(), setfill(), left, right...

	// Event Loop
	while (true)
	{
		handle<char>(out, in, F("char"));
		handle<uint16_t>(out, in, F("uint16_t"));
		handle<int16_t>(out, in, F("int16_t"));
		handle<uint32_t>(out, in, F("uint32_t"));
		handle<int32_t>(out, in, F("int32_t"));
		handle<bool>(out, in, F("bool"));

		time::delay_ms(1000);
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/zlib/google/zip_reader.h"

#include <utility>

#include "base/files/file_path.h"
#include "base/strings/string_util.h"

#include "contrib/minizip/unzip.h"

// This file is a stripped down version of zip_reader.cc from Chromium: https://source.chromium.org/chromium/chromium/src/+/main:third_party/zlib/google/zip_reader.cc.
// It also contains code to wrap memory around the file interface from zip_internal.cc: https://source.chromium.org/chromium/chromium/src/+/main:third_party/zlib/google/zip_internal.cc
// It only contains code required to read a zip file using zlib and replaces the usage of other Chromium code not present in mini_chromium.

namespace zip {

ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip,
                                const unz_file_info& raw_file_info)
    : file_path_(file_name_in_zip),
      is_directory_(false) {

  original_size_ = raw_file_info.uncompressed_size;

  // Directory entries in zip files end with "/".
  if (file_name_in_zip.size() > 0) {
    is_directory_ = file_name_in_zip.back() == '/';
  }
}

// START from internal.cc

// A struct that contains data required for zlib functions to extract files from
// a zip archive stored in memory directly. The following I/O API functions
// expect their opaque parameters refer to this struct.
struct ZipBuffer {
  const char* data;  // weak
  size_t length;
  size_t offset;
};

// Opens the specified file. When this function returns a non-NULL pointer, zlib
// uses this pointer as a stream parameter while compressing or uncompressing
// data. (Returning NULL represents an error.) This function initializes the
// given opaque parameter and returns it because this parameter stores all
// information needed for uncompressing data. (This function does not support
// writing compressed data and it returns NULL for this case.)
void* OpenZipBuffer(void* opaque, const char* /*filename*/, int mode) {
  if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) {
    return NULL;
  }
  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
  if (!buffer || !buffer->data || !buffer->length)
    return NULL;
  buffer->offset = 0;
  return opaque;
}

// Reads compressed data from the specified stream. This function copies data
// refered by the opaque parameter and returns the size actually copied.
uLong ReadZipBuffer(void* opaque, void* /*stream*/, void* buf, uLong size) {
  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
  DCHECK_LE(buffer->offset, buffer->length);
  size_t remaining_bytes = buffer->length - buffer->offset;
  if (!buffer || !buffer->data || !remaining_bytes)
    return 0;
  size = std::min(size, static_cast<uLong>(remaining_bytes));
  memcpy(buf, &buffer->data[buffer->offset], size);
  buffer->offset += size;
  return size;
}

// Returns the offset from the beginning of the data.
long GetOffsetOfZipBuffer(void* opaque, void* /*stream*/) {
  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
  if (!buffer)
    return -1;
  return static_cast<long>(buffer->offset);
}

// Moves the current offset to the specified position.
long SeekZipBuffer(void* opaque, void* /*stream*/, uLong offset, int origin) {
  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
  if (!buffer)
    return -1;
  if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
    buffer->offset = std::min(buffer->offset + static_cast<size_t>(offset),
                              buffer->length);
    return 0;
  }
  if (origin == ZLIB_FILEFUNC_SEEK_END) {
    buffer->offset = (buffer->length > offset) ? buffer->length - offset : 0;
    return 0;
  }
  if (origin == ZLIB_FILEFUNC_SEEK_SET) {
    buffer->offset = std::min(buffer->length, static_cast<size_t>(offset));
    return 0;
  }
  return -1;
}

// Closes the input offset and deletes all resources used for compressing or
// uncompressing data. This function deletes the ZipBuffer object referred by
// the opaque parameter since zlib deletes the unzFile object and it does not
// use this object any longer.
int CloseZipBuffer(void* opaque, void* /*stream*/) {
  if (opaque)
    free(opaque);
  return 0;
}

// Returns the last error happened when reading or writing data. This function
// always returns zero, which means there are not any errors.
int GetErrorOfZipBuffer(void* /*opaque*/, void* /*stream*/) {
  return 0;
}
// END from internal.cc

ZipReader::ZipReader() {
  Reset();
}

ZipReader::~ZipReader() {
  Close();
}

bool ZipReader::OpenFromString(const std::string& data) {
  if (data.empty()) {
    return false;
  }

  ZipBuffer* buffer = static_cast<ZipBuffer*>(malloc(sizeof(ZipBuffer)));
  if (!buffer) {
    return false;
  }
  buffer->data = data.data();
  buffer->length = data.length();
  buffer->offset = 0;

  zlib_filefunc_def zip_functions;
  zip_functions.zopen_file = OpenZipBuffer;
  zip_functions.zread_file = ReadZipBuffer;
  // Removed WriteZipBuffer as it is not required for reading zip files.
  zip_functions.ztell_file = GetOffsetOfZipBuffer;
  zip_functions.zseek_file = SeekZipBuffer;
  zip_functions.zclose_file = CloseZipBuffer;
  zip_functions.zerror_file = GetErrorOfZipBuffer;
  zip_functions.opaque = static_cast<void*>(buffer);
  zip_file_ = unzOpen2(NULL, &zip_functions);

  unz_global_info zip_info = {};  // Zero-clear.
  if (unzGetGlobalInfo(zip_file_, &zip_info) != UNZ_OK) {
    return false;
  }
  num_entries_ = zip_info.number_entry;

  if (num_entries_ < 0)
    return false;

  // We are already at the end if the zip file is empty.
  reached_end_ = (num_entries_ == 0);

  return true;
}

void ZipReader::Close() {
  if (zip_file_) {
    unzClose(zip_file_);
  }
  Reset();
}

bool ZipReader::HasMore() {
  return !reached_end_;
}

bool ZipReader::AdvanceToNextEntry() {
  DCHECK(zip_file_);

  // Should not go further if we already reached the end.
  if (reached_end_)
    return false;

  unz_file_pos position = {};
  if (unzGetFilePos(zip_file_, &position) != UNZ_OK)
    return false;
  const int current_entry_index = position.num_of_file;
  // If we are currently at the last entry, then the next position is the
  // end of the zip file, so mark that we reached the end.
  if (current_entry_index + 1 == num_entries_) {
    reached_end_ = true;
  } else {
    DCHECK_LT(current_entry_index + 1, num_entries_);
    if (unzGoToNextFile(zip_file_) != UNZ_OK) {
      return false;
    }
  }
  current_entry_info_.reset();
  return true;
}

bool ZipReader::OpenCurrentEntryInZip() {
  DCHECK(zip_file_);

  unz_file_info raw_file_info = {};
  constexpr int kZipMaxPath = 256;
  char raw_file_name_in_zip[kZipMaxPath] = {};
  const int result = unzGetCurrentFileInfo(zip_file_,
                                           &raw_file_info,
                                           raw_file_name_in_zip,
                                           sizeof(raw_file_name_in_zip) - 1,
                                           NULL,  // extraField.
                                           0,  // extraFieldBufferSize.
                                           NULL,  // szComment.
                                           0);  // commentBufferSize.

  if (result != UNZ_OK)
    return false;
  if (raw_file_name_in_zip[0] == '\0')
    return false;
  current_entry_info_.reset(
      new EntryInfo(raw_file_name_in_zip, raw_file_info));
  return true;
}

bool ZipReader::ExtractCurrentEntryToString(/* not used*/ uint64_t max_read_bytes,
                                            std::string* output) const {
  DCHECK(output);
  DCHECK(zip_file_);

  output->clear();

  if (max_read_bytes == 0) {
    return true;
  }

  if (current_entry_info_->is_directory()) {
    return true;
  }

  const int open_result = unzOpenCurrentFile(zip_file_);
  if (open_result != UNZ_OK) {
    return false;
  }

  constexpr int kZipBufSize = 8192;
  char buf[kZipBufSize];
  bool entire_file_extracted = false;

  while (true) {
    const int num_bytes_read =
        unzReadCurrentFile(zip_file_, buf, kZipBufSize);

    if (num_bytes_read == 0) {
      entire_file_extracted = true;
      break;
    } else if (num_bytes_read < 0) {
      // If num_bytes_read < 0, then it's a specific UNZ_* error code.
      break;
    } else if (num_bytes_read > 0) {
      output->append(buf, num_bytes_read);
    }
  }

  unzCloseCurrentFile(zip_file_);
  return entire_file_extracted;
}

void ZipReader::Reset() {
  zip_file_ = NULL;
  num_entries_ = 0;
  reached_end_ = false;
  current_entry_info_.reset();
}
}  // namespace zip
<commit_msg>Porting zip_reader.cc to Windows (#37)<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/zlib/google/zip_reader.h"

#include <utility>

#include "base/files/file_path.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"

#include "contrib/minizip/unzip.h"

// This file is a stripped down version of zip_reader.cc from Chromium: https://source.chromium.org/chromium/chromium/src/+/main:third_party/zlib/google/zip_reader.cc.
// It also contains code to wrap memory around the file interface from zip_internal.cc: https://source.chromium.org/chromium/chromium/src/+/main:third_party/zlib/google/zip_internal.cc
// It only contains code required to read a zip file using zlib and replaces the usage of other Chromium code not present in mini_chromium.

namespace zip {

ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip,
                                const unz_file_info& raw_file_info)
#if defined(_WIN32)
    : file_path_(base::UTF8ToWide(file_name_in_zip)),
#else
    : file_path_(file_name_in_zip),
#endif  // _WIN32
      is_directory_(false) {

  original_size_ = raw_file_info.uncompressed_size;

  // Directory entries in zip files end with "/".
  if (file_name_in_zip.size() > 0) {
    is_directory_ = file_name_in_zip.back() == '/';
  }
}

// START from internal.cc

// A struct that contains data required for zlib functions to extract files from
// a zip archive stored in memory directly. The following I/O API functions
// expect their opaque parameters refer to this struct.
struct ZipBuffer {
  const char* data;  // weak
  size_t length;
  size_t offset;
};

// Opens the specified file. When this function returns a non-NULL pointer, zlib
// uses this pointer as a stream parameter while compressing or uncompressing
// data. (Returning NULL represents an error.) This function initializes the
// given opaque parameter and returns it because this parameter stores all
// information needed for uncompressing data. (This function does not support
// writing compressed data and it returns NULL for this case.)
void* OpenZipBuffer(void* opaque, const char* /*filename*/, int mode) {
  if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) {
    return NULL;
  }
  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
  if (!buffer || !buffer->data || !buffer->length)
    return NULL;
  buffer->offset = 0;
  return opaque;
}

// Reads compressed data from the specified stream. This function copies data
// refered by the opaque parameter and returns the size actually copied.
uLong ReadZipBuffer(void* opaque, void* /*stream*/, void* buf, uLong size) {
  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
  DCHECK_LE(buffer->offset, buffer->length);
  size_t remaining_bytes = buffer->length - buffer->offset;
  if (!buffer || !buffer->data || !remaining_bytes)
    return 0;
  size = std::min(size, static_cast<uLong>(remaining_bytes));
  memcpy(buf, &buffer->data[buffer->offset], size);
  buffer->offset += size;
  return size;
}

// Returns the offset from the beginning of the data.
long GetOffsetOfZipBuffer(void* opaque, void* /*stream*/) {
  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
  if (!buffer)
    return -1;
  return static_cast<long>(buffer->offset);
}

// Moves the current offset to the specified position.
long SeekZipBuffer(void* opaque, void* /*stream*/, uLong offset, int origin) {
  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
  if (!buffer)
    return -1;
  if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
    buffer->offset = std::min(buffer->offset + static_cast<size_t>(offset),
                              buffer->length);
    return 0;
  }
  if (origin == ZLIB_FILEFUNC_SEEK_END) {
    buffer->offset = (buffer->length > offset) ? buffer->length - offset : 0;
    return 0;
  }
  if (origin == ZLIB_FILEFUNC_SEEK_SET) {
    buffer->offset = std::min(buffer->length, static_cast<size_t>(offset));
    return 0;
  }
  return -1;
}

// Closes the input offset and deletes all resources used for compressing or
// uncompressing data. This function deletes the ZipBuffer object referred by
// the opaque parameter since zlib deletes the unzFile object and it does not
// use this object any longer.
int CloseZipBuffer(void* opaque, void* /*stream*/) {
  if (opaque)
    free(opaque);
  return 0;
}

// Returns the last error happened when reading or writing data. This function
// always returns zero, which means there are not any errors.
int GetErrorOfZipBuffer(void* /*opaque*/, void* /*stream*/) {
  return 0;
}
// END from internal.cc

ZipReader::ZipReader() {
  Reset();
}

ZipReader::~ZipReader() {
  Close();
}

bool ZipReader::OpenFromString(const std::string& data) {
  if (data.empty()) {
    return false;
  }

  ZipBuffer* buffer = static_cast<ZipBuffer*>(malloc(sizeof(ZipBuffer)));
  if (!buffer) {
    return false;
  }
  buffer->data = data.data();
  buffer->length = data.length();
  buffer->offset = 0;

  zlib_filefunc_def zip_functions;
  zip_functions.zopen_file = OpenZipBuffer;
  zip_functions.zread_file = ReadZipBuffer;
  // Removed WriteZipBuffer as it is not required for reading zip files.
  zip_functions.ztell_file = GetOffsetOfZipBuffer;
  zip_functions.zseek_file = SeekZipBuffer;
  zip_functions.zclose_file = CloseZipBuffer;
  zip_functions.zerror_file = GetErrorOfZipBuffer;
  zip_functions.opaque = static_cast<void*>(buffer);
  zip_file_ = unzOpen2(NULL, &zip_functions);

  unz_global_info zip_info = {};  // Zero-clear.
  if (unzGetGlobalInfo(zip_file_, &zip_info) != UNZ_OK) {
    return false;
  }
  num_entries_ = zip_info.number_entry;

  if (num_entries_ < 0)
    return false;

  // We are already at the end if the zip file is empty.
  reached_end_ = (num_entries_ == 0);

  return true;
}

void ZipReader::Close() {
  if (zip_file_) {
    unzClose(zip_file_);
  }
  Reset();
}

bool ZipReader::HasMore() {
  return !reached_end_;
}

bool ZipReader::AdvanceToNextEntry() {
  DCHECK(zip_file_);

  // Should not go further if we already reached the end.
  if (reached_end_)
    return false;

  unz_file_pos position = {};
  if (unzGetFilePos(zip_file_, &position) != UNZ_OK)
    return false;
  const int current_entry_index = position.num_of_file;
  // If we are currently at the last entry, then the next position is the
  // end of the zip file, so mark that we reached the end.
  if (current_entry_index + 1 == num_entries_) {
    reached_end_ = true;
  } else {
    DCHECK_LT(current_entry_index + 1, num_entries_);
    if (unzGoToNextFile(zip_file_) != UNZ_OK) {
      return false;
    }
  }
  current_entry_info_.reset();
  return true;
}

bool ZipReader::OpenCurrentEntryInZip() {
  DCHECK(zip_file_);

  unz_file_info raw_file_info = {};
  constexpr int kZipMaxPath = 256;
  char raw_file_name_in_zip[kZipMaxPath] = {};
  const int result = unzGetCurrentFileInfo(zip_file_,
                                           &raw_file_info,
                                           raw_file_name_in_zip,
                                           sizeof(raw_file_name_in_zip) - 1,
                                           NULL,  // extraField.
                                           0,  // extraFieldBufferSize.
                                           NULL,  // szComment.
                                           0);  // commentBufferSize.

  if (result != UNZ_OK)
    return false;
  if (raw_file_name_in_zip[0] == '\0')
    return false;
  current_entry_info_.reset(
      new EntryInfo(raw_file_name_in_zip, raw_file_info));
  return true;
}

bool ZipReader::ExtractCurrentEntryToString(/* not used*/ uint64_t max_read_bytes,
                                            std::string* output) const {
  DCHECK(output);
  DCHECK(zip_file_);

  output->clear();

  if (max_read_bytes == 0) {
    return true;
  }

  if (current_entry_info_->is_directory()) {
    return true;
  }

  const int open_result = unzOpenCurrentFile(zip_file_);
  if (open_result != UNZ_OK) {
    return false;
  }

  constexpr int kZipBufSize = 8192;
  char buf[kZipBufSize];
  bool entire_file_extracted = false;

  while (true) {
    const int num_bytes_read =
        unzReadCurrentFile(zip_file_, buf, kZipBufSize);

    if (num_bytes_read == 0) {
      entire_file_extracted = true;
      break;
    } else if (num_bytes_read < 0) {
      // If num_bytes_read < 0, then it's a specific UNZ_* error code.
      break;
    } else if (num_bytes_read > 0) {
      output->append(buf, num_bytes_read);
    }
  }

  unzCloseCurrentFile(zip_file_);
  return entire_file_extracted;
}

void ZipReader::Reset() {
  zip_file_ = NULL;
  num_entries_ = 0;
  reached_end_ = false;
  current_entry_info_.reset();
}
}  // namespace zip
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: extendapplicationenvironment.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: obo $ $Date: 2008-01-07 09:48:23 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2007 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "precompiled_tools.hxx"
#include "sal/config.h"

#include <stdlib.h>
    // not <cstdlib> as putenv is POSIX-only; setenv instead of putenv would be
    // better but is not supported by Solaris 9 and earlier

#if defined UNX
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#endif

#include "osl/process.h"
#include "osl/thread.h"
#include "rtl/string.h"
#include "rtl/string.hxx"
#include "rtl/textcvt.h"
#include "rtl/ustring.hxx"
#include "sal/types.h"
#include "tools/extendapplicationenvironment.hxx"

namespace tools {

void extendApplicationEnvironment() {
#if defined UNX
    // Try to set RLIMIT_NOFILE as large as possible (failure is harmless):
    rlimit l;
    if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
        l.rlim_cur = l.rlim_max;
        setrlimit(RLIMIT_NOFILE, &l);
    }
#endif

    // Make sure URE_BOOTSTRAP environment variable is set (failure is fatal):
    if (getenv("URE_BOOTSTRAP") == NULL) {
        rtl::OUString p;
        if (osl_getExecutableFile(&p.pData) != osl_Process_E_None) {
            abort();
        }
        sal_Int32 i = p.lastIndexOf('/');
        if (i >= 0) {
            p = p.copy(0, i + 1);
        }
        rtl::OString s;
        if (!p.convertToString(
                &s, osl_getThreadTextEncoding(),
                RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
                | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
        {
            abort();
        }
        rtl::OString env(RTL_CONSTASCII_STRINGPARAM("URE_BOOTSTRAP="));
        env += s;
        env += SAL_CONFIGFILE("fundamental");
        rtl_string_acquire(env.pData); // argument to putenv must leak
        if (putenv(const_cast< char * >(env.getStr())) != 0) {
            abort();
        }
    }
}

}
<commit_msg>#i10000# restore lost changes from sb83<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: extendapplicationenvironment.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2008-03-19 12:29:04 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2007 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "precompiled_tools.hxx"
#include "sal/config.h"

#include <stdlib.h>
    // not <cstdlib> as putenv is POSIX-only; setenv instead of putenv would be
    // better but is not supported by Solaris 9 and earlier

#if defined UNX
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#endif

#include "osl/process.h"
#include "osl/thread.h"
#include "rtl/bootstrap.hxx"
#include "rtl/string.hxx"
#include "rtl/textcvt.h"
#include "rtl/ustring.h"
#include "rtl/ustring.hxx"
#include "sal/types.h"
#include "tools/extendapplicationenvironment.hxx"

namespace tools {

void extendApplicationEnvironment() {
#if defined UNX
    // Try to set RLIMIT_NOFILE as large as possible (failure is harmless):
    rlimit l;
    if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
        l.rlim_cur = l.rlim_max;
        setrlimit(RLIMIT_NOFILE, &l);
    }
#endif

    // Make sure URE_BOOTSTRAP environment variable is set (failure is fatal):
    rtl::OUString env(RTL_CONSTASCII_USTRINGPARAM("URE_BOOTSTRAP="));
    rtl::OUString uri;
    if (rtl::Bootstrap::get(
            rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("URE_BOOTSTRAP")), uri))
    {
        env += uri;
    } else {
        if (osl_getExecutableFile(&uri.pData) != osl_Process_E_None) {
            abort();
        }
        sal_Int32 i = uri.lastIndexOf('/');
        if (i >= 0) {
            uri = uri.copy(0, i + 1);
        }
        env += uri;
        env += rtl::OUString(
            RTL_CONSTASCII_USTRINGPARAM(SAL_CONFIGFILE("fundamental")));
    }
    rtl::OString s;
    if (!env.convertToString(
            &s, osl_getThreadTextEncoding(),
            RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
            | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
    {
        abort();
    }
    rtl_string_acquire(s.pData); // argument to putenv must leak
    if (putenv(const_cast< char * >(s.getStr())) != 0) {
        abort();
    }
}

}
<|endoftext|>


<commit_before>#pragma once

#include <stdint.h>

/** @file bts/blockchain/config.hpp
 *  @brief Defines global constants that determine blockchain behavior
 */
#define BTS_BLOCKCHAIN_VERSION                          (104)
#define BTS_WALLET_VERSION                              (100)
#define BTS_BLOCKCHAIN_DATABASE_VERSION                 (109)

/**
 *  The address prepended to string representation of
 *  addresses.
 *
 *  Changing these parameters will result in a hard fork.
 */
#define BTS_ADDRESS_PREFIX                                 "XTS"
#define BTS_BLOCKCHAIN_SYMBOL                              "XTS"
#define BTS_BLOCKCHAIN_NAME                                "BitShares XTS"
#define BTS_BLOCKCHAIN_DESCRIPTION                         "Stake in future BitShares X chains"
#define BTS_BLOCKCHAIN_PRECISION                           (100000)
#define BTS_BLOCKCHAIN_MAX_TRANSACTION_EXPIRATION_SEC      (60*60*24*2)
#define BTS_BLOCKCHAIN_DEFAULT_TRANSACTION_EXPIRATION_SEC  (60*60*2)

/**
 * The number of delegates that the blockchain is designed to support
 */
#define BTS_BLOCKCHAIN_NUM_DELEGATES                    (101)
#define BTS_BLOCKCHAIN_MAX_SLATE_SIZE                   (BTS_BLOCKCHAIN_NUM_DELEGATES)

/**
 * To prevent a delegate from producing blocks on split network,
 * we check the connection count.  This means no blocks get produced
 * until at least a minimum number of clients are on line.
 */
#define BTS_MIN_DELEGATE_CONNECTION_COUNT               (5)

/**
 * Defines the number of seconds that should elapse between blocks
 */
#define BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC               int64_t(15)

/**
 *  The maximum size of the raw data contained in the blockchain, this size is
 *  notional based upon the serilized size of all user-generated transactions in
 *  all blocks for one year.
 *
 *  Actual size on disk will likely be 2 or 3x this size due to indexes and other
 *  storeage overhead.
 *
 *  Adjusting this value will change the effective fee charged on transactions
 */
#define BTS_BLOCKCHAIN_MAX_SIZE                         (1024*1024*1024*100ll) // 100 GB
#define BTS_BLOCKCHAIN_MIN_NAME_SIZE                    (1)
#define BTS_BLOCKCHAIN_MAX_NAME_SIZE                    (63)
#define BTS_BLOCKCHAIN_MAX_NAME_DATA_SIZE               (1024*64)
#define BTS_BLOCKCHAIN_MAX_MEMO_SIZE                    (19) // bytes
#define BTS_BLOCKCHAIN_MAX_SYMBOL_SIZE                  (5) // characters
#define BTS_BLOCKCHAIN_MIN_SYMBOL_SIZE                  (3) // characters
#define BTS_BLOCKCHAIN_PROPOSAL_VOTE_MESSAGE_MAX_SIZE   (1024) // bytes

/**
 *  The maximum amount that can be issued for user assets.
 *
 *  10^18 / 2^63 < 1
 */
#define BTS_BLOCKCHAIN_MAX_SHARES                       (1000*1000*1000ll*1000*1000ll)

/**
 * Initial shares read from the genesis block are scaled to this number. It is divided
 * by 100 so that new shares may be issued without exceeding BTS_BLOCKCHAIN_MAX_SHARES
 */
#define BTS_BLOCKCHAIN_INITIAL_SHARES                   (BTS_BLOCKCHAIN_MAX_SHARES / 5)

/**
 *  The number of blocks expected per hour based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_HOUR                  ((60*60)/BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC)

/**
 *  The number of blocks expected per day based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_DAY                   (BTS_BLOCKCHAIN_BLOCKS_PER_HOUR*24ll)

/**
 * The number of blocks expected per year based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_YEAR                  (BTS_BLOCKCHAIN_BLOCKS_PER_DAY*365ll)

/** defines the maximum block size allowed, 24 MB per hour */
//#define BTS_BLOCKCHAIN_MAX_BLOCK_SIZE                   (24 * 1024*1024 / BTS_BLOCKCHAIN_BLOCKS_PER_HOUR)
#define BTS_BLOCKCHAIN_MAX_BLOCK_SIZE                   (30*64*1024)  // 2 min blocks, this is 64K max block size

/** defines the target block size, fees will be adjusted to maintain this target */
#define BTS_BLOCKCHAIN_TARGET_BLOCK_SIZE                (BTS_BLOCKCHAIN_MAX_BLOCK_SIZE/2)

#define BTS_BLOCKCHAIN_BLOCK_REWARD                     (BTS_BLOCKCHAIN_MAX_BLOCK_SIZE) //10000 // (BTS_BLOCKCHAIN_INITIAL_SHARES/BTS_BLOCKCHAIN_BLOCKS_PER_YEAR)
#define BTS_BLOCKCHAIN_INACTIVE_FEE_APR                 (10)  // 10% per year

/**
 *  defines the min fee in milli-shares per byte
 */
#define BTS_BLOCKCHAIN_MIN_FEE                          (1000)

/**
 *  Defined so that a delegate must produce 100 blocks to break even.
 */
#define BTS_BLOCKCHAIN_DELEGATE_REGISTRATION_FEE        (BTS_BLOCKCHAIN_BLOCK_REWARD)

/**
 *  Defines the fee required to register a asset, this fee is set to discourage anyone from
 *  registering all of the symbols.  If the asset is not worth at least 100 blocks worth
 *  of mining fees then it really isn't worth the networks time.
 */
#define BTS_BLOCKCHAIN_ASSET_REGISTRATION_FEE           (BTS_BLOCKCHAIN_BLOCK_REWARD)
<commit_msg>adjust max block size to yield about 2 trx/sec maximum<commit_after>#pragma once

#include <stdint.h>

/** @file bts/blockchain/config.hpp
 *  @brief Defines global constants that determine blockchain behavior
 */
#define BTS_BLOCKCHAIN_VERSION                          (104)
#define BTS_WALLET_VERSION                              (100)
#define BTS_BLOCKCHAIN_DATABASE_VERSION                 (109)

/**
 *  The address prepended to string representation of
 *  addresses.
 *
 *  Changing these parameters will result in a hard fork.
 */
#define BTS_ADDRESS_PREFIX                                 "XTS"
#define BTS_BLOCKCHAIN_SYMBOL                              "XTS"
#define BTS_BLOCKCHAIN_NAME                                "BitShares XTS"
#define BTS_BLOCKCHAIN_DESCRIPTION                         "Stake in future BitShares X chains"
#define BTS_BLOCKCHAIN_PRECISION                           (100000)
#define BTS_BLOCKCHAIN_MAX_TRANSACTION_EXPIRATION_SEC      (60*60*24*2)
#define BTS_BLOCKCHAIN_DEFAULT_TRANSACTION_EXPIRATION_SEC  (60*60*2)

/**
 * The number of delegates that the blockchain is designed to support
 */
#define BTS_BLOCKCHAIN_NUM_DELEGATES                    (101)
#define BTS_BLOCKCHAIN_MAX_SLATE_SIZE                   (BTS_BLOCKCHAIN_NUM_DELEGATES)

/**
 * To prevent a delegate from producing blocks on split network,
 * we check the connection count.  This means no blocks get produced
 * until at least a minimum number of clients are on line.
 */
#define BTS_MIN_DELEGATE_CONNECTION_COUNT               (5)

/**
 * Defines the number of seconds that should elapse between blocks
 */
#define BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC               int64_t(15)

/**
 *  The maximum size of the raw data contained in the blockchain, this size is
 *  notional based upon the serilized size of all user-generated transactions in
 *  all blocks for one year.
 *
 *  Actual size on disk will likely be 2 or 3x this size due to indexes and other
 *  storeage overhead.
 *
 *  Adjusting this value will change the effective fee charged on transactions
 */
#define BTS_BLOCKCHAIN_MAX_SIZE                         (1024*1024*1024*100ll) // 100 GB
#define BTS_BLOCKCHAIN_MIN_NAME_SIZE                    (1)
#define BTS_BLOCKCHAIN_MAX_NAME_SIZE                    (63)
#define BTS_BLOCKCHAIN_MAX_NAME_DATA_SIZE               (1024*64)
#define BTS_BLOCKCHAIN_MAX_MEMO_SIZE                    (19) // bytes
#define BTS_BLOCKCHAIN_MAX_SYMBOL_SIZE                  (5) // characters
#define BTS_BLOCKCHAIN_MIN_SYMBOL_SIZE                  (3) // characters
#define BTS_BLOCKCHAIN_PROPOSAL_VOTE_MESSAGE_MAX_SIZE   (1024) // bytes

/**
 *  The maximum amount that can be issued for user assets.
 *
 *  10^18 / 2^63 < 1
 */
#define BTS_BLOCKCHAIN_MAX_SHARES                       (1000*1000*1000ll*1000*1000ll)

/**
 * Initial shares read from the genesis block are scaled to this number. It is divided
 * by 100 so that new shares may be issued without exceeding BTS_BLOCKCHAIN_MAX_SHARES
 */
#define BTS_BLOCKCHAIN_INITIAL_SHARES                   (BTS_BLOCKCHAIN_MAX_SHARES / 5)

/**
 *  The number of blocks expected per hour based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_HOUR                  ((60*60)/BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC)

/**
 *  The number of blocks expected per day based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_DAY                   (BTS_BLOCKCHAIN_BLOCKS_PER_HOUR*24ll)

/**
 * The number of blocks expected per year based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_YEAR                  (BTS_BLOCKCHAIN_BLOCKS_PER_DAY*365ll)

/** defines the maximum block size allowed, 2 MB per hour */
#define BTS_BLOCKCHAIN_MAX_BLOCK_SIZE                   ( 2 * 1024*1024 / BTS_BLOCKCHAIN_BLOCKS_PER_HOUR)

/** defines the target block size, fees will be adjusted to maintain this target */
#define BTS_BLOCKCHAIN_TARGET_BLOCK_SIZE                (BTS_BLOCKCHAIN_MAX_BLOCK_SIZE/2)

#define BTS_BLOCKCHAIN_BLOCK_REWARD                     (BTS_BLOCKCHAIN_MAX_BLOCK_SIZE) //10000 // (BTS_BLOCKCHAIN_INITIAL_SHARES/BTS_BLOCKCHAIN_BLOCKS_PER_YEAR)
#define BTS_BLOCKCHAIN_INACTIVE_FEE_APR                 (10)  // 10% per year

/**
 *  defines the min fee in milli-shares per byte
 */
#define BTS_BLOCKCHAIN_MIN_FEE                          (1000)

/**
 *  Defined so that a delegate must produce 100 blocks to break even.
 */
#define BTS_BLOCKCHAIN_DELEGATE_REGISTRATION_FEE        (BTS_BLOCKCHAIN_BLOCK_REWARD)

/**
 *  Defines the fee required to register a asset, this fee is set to discourage anyone from
 *  registering all of the symbols.  If the asset is not worth at least 100 blocks worth
 *  of mining fees then it really isn't worth the networks time.
 */
#define BTS_BLOCKCHAIN_ASSET_REGISTRATION_FEE           (BTS_BLOCKCHAIN_BLOCK_REWARD)
<|endoftext|>


<commit_before>#include "AutoGenerated.inc"

#include "llvm/System/Path.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace llvmc {
  extern char *ProgramName;
}

// Returns the platform specific directory separator via #ifdefs.
static std::string GetDirSeparator(void) {
  return "/";
}

namespace hooks {
// Get the dir where c16 executables reside.
std::string GetBinDir (void) {
  // Construct a Path object from the program name.
  void *P = (void*) (intptr_t) GetBinDir;
  sys::Path ProgramFullPath
    = sys::Path::GetMainExecutable(llvmc::ProgramName, P);

  // Get the dir name for the program. It's last component should be 'bin'.
  std::string BinDir = ProgramFullPath.getDirname();

  // llvm::errs() << "BinDir: " << BinDir << '\n';
  return BinDir + GetDirSeparator();
}

// Get the Top-level Installation dir for c16.
std::string GetInstallDir (void) {
  sys::Path BinDirPath = sys::Path(GetBinDir());

  // Go one more level up to get the install dir.
  std::string InstallDir  = BinDirPath.getDirname();

  return InstallDir + GetDirSeparator();
}

// Get the dir where the c16 header files reside.
std::string GetStdHeadersDir (void) {
  return GetInstallDir() + "include";
}

// Get the dir where the assembler header files reside.
std::string GetStdAsmHeadersDir (void) {
  return GetInstallDir() + "inc";
}

// Get the dir where the linker scripts reside.
std::string GetStdLinkerScriptsDir (void) {
  return GetInstallDir() + "lkr";
}

// Get the dir where startup code, intrinsics and lib reside.
std::string GetStdLibsDir (void) {
  return GetInstallDir() + "lib";
}
}
<commit_msg>Return dir separator as per platform.<commit_after>#include "AutoGenerated.inc"

#include "llvm/System/Path.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace llvmc {
  extern char *ProgramName;
}

// Returns the platform specific directory separator via #ifdefs.
static std::string GetDirSeparator(void) {
#ifdef __linux__
  return "/";
#else
  return "\\";
#endif
}

namespace hooks {
// Get the dir where c16 executables reside.
std::string GetBinDir (void) {
  // Construct a Path object from the program name.
  void *P = (void*) (intptr_t) GetBinDir;
  sys::Path ProgramFullPath
    = sys::Path::GetMainExecutable(llvmc::ProgramName, P);

  // Get the dir name for the program. It's last component should be 'bin'.
  std::string BinDir = ProgramFullPath.getDirname();

  // llvm::errs() << "BinDir: " << BinDir << '\n';
  return BinDir + GetDirSeparator();
}

// Get the Top-level Installation dir for c16.
std::string GetInstallDir (void) {
  sys::Path BinDirPath = sys::Path(GetBinDir());

  // Go one more level up to get the install dir.
  std::string InstallDir  = BinDirPath.getDirname();

  return InstallDir + GetDirSeparator();
}

// Get the dir where the c16 header files reside.
std::string GetStdHeadersDir (void) {
  return GetInstallDir() + "include";
}

// Get the dir where the assembler header files reside.
std::string GetStdAsmHeadersDir (void) {
  return GetInstallDir() + "inc";
}

// Get the dir where the linker scripts reside.
std::string GetStdLinkerScriptsDir (void) {
  return GetInstallDir() + "lkr";
}

// Get the dir where startup code, intrinsics and lib reside.
std::string GetStdLibsDir (void) {
  return GetInstallDir() + "lib";
}
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/utf_string_conversions.h"
#include "chrome/test/live_sync/live_autofill_sync_test.h"

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest, Client1HasData) {
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";

  AutofillKeys keys;
  keys.insert(AutofillKey("name0", "value0"));
  keys.insert(AutofillKey("name0", "value1"));
  keys.insert(AutofillKey("name1", "value2"));
  keys.insert(AutofillKey(WideToUTF16(L"Sigur R\u00F3s"),
                          WideToUTF16(L"\u00C1g\u00E6tis byrjun")));
  AddFormFieldsToWebData(GetWebDataService(0), keys);

  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  ASSERT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients()));

  AutofillKeys wd1_keys;
  GetAllAutofillKeys(GetWebDataService(1), &wd1_keys);
  EXPECT_EQ(keys, wd1_keys);
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest, BothHaveData) {
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";

  AutofillKeys keys1;
  keys1.insert(AutofillKey("name0", "value0"));
  keys1.insert(AutofillKey("name0", "value1"));
  keys1.insert(AutofillKey("name1", "value2"));
  AddFormFieldsToWebData(GetWebDataService(0), keys1);

  AutofillKeys keys2;
  keys2.insert(AutofillKey("name0", "value1"));
  keys2.insert(AutofillKey("name1", "value2"));
  keys2.insert(AutofillKey("name2", "value3"));
  keys2.insert(AutofillKey("name3", "value3"));
  AddFormFieldsToWebData(GetWebDataService(1), keys2);

  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  EXPECT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients()));

  AutofillKeys expected_keys;
  expected_keys.insert(AutofillKey("name0", "value0"));
  expected_keys.insert(AutofillKey("name0", "value1"));
  expected_keys.insert(AutofillKey("name1", "value2"));
  expected_keys.insert(AutofillKey("name2", "value3"));
  expected_keys.insert(AutofillKey("name3", "value3"));

  AutofillKeys wd0_keys;
  GetAllAutofillKeys(GetWebDataService(0), &wd0_keys);
  EXPECT_EQ(expected_keys, wd0_keys);

  AutofillKeys wd1_keys;
  GetAllAutofillKeys(GetWebDataService(1), &wd1_keys);
  EXPECT_EQ(expected_keys, wd1_keys);
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest, Steady) {
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";

  // Client0 adds a key.
  AutofillKeys add_one_key;
  add_one_key.insert(AutofillKey("name0", "value0"));
  AddFormFieldsToWebData(GetWebDataService(0), add_one_key);
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  AutofillKeys expected_keys;
  expected_keys.insert(AutofillKey("name0", "value0"));

  AutofillKeys keys;
  GetAllAutofillKeys(GetWebDataService(0), &keys);
  EXPECT_EQ(expected_keys, keys);
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(1), &keys);
  EXPECT_EQ(expected_keys, keys);

  // Client1 adds a key.
  add_one_key.clear();
  add_one_key.insert(AutofillKey("name1", "value1"));
  AddFormFieldsToWebData(GetWebDataService(1), add_one_key);
  EXPECT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0)));

  expected_keys.insert(AutofillKey("name1", "value1"));
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(0), &keys);
  EXPECT_EQ(expected_keys, keys);
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(1), &keys);
  EXPECT_EQ(expected_keys, keys);

  // Client0 adds a key with the same name.
  add_one_key.clear();
  add_one_key.insert(AutofillKey("name1", "value2"));
  AddFormFieldsToWebData(GetWebDataService(0), add_one_key);
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  expected_keys.insert(AutofillKey("name1", "value2"));
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(0), &keys);
  EXPECT_EQ(expected_keys, keys);
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(1), &keys);
  EXPECT_EQ(expected_keys, keys);

  // Client1 removes a key.
  RemoveKeyFromWebData(GetWebDataService(1), AutofillKey("name1", "value1"));
  EXPECT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0)));

  expected_keys.erase(AutofillKey("name1", "value1"));
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(0), &keys);
  EXPECT_EQ(expected_keys, keys);
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(1), &keys);
  EXPECT_EQ(expected_keys, keys);

  // Client0 removes the rest.
  RemoveKeyFromWebData(GetWebDataService(0), AutofillKey("name0", "value0"));
  RemoveKeyFromWebData(GetWebDataService(0), AutofillKey("name1", "value2"));
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  keys.clear();
  GetAllAutofillKeys(GetWebDataService(0), &keys);
  EXPECT_EQ(0U, keys.size());
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(1), &keys);
  EXPECT_EQ(0U, keys.size());
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest, ProfileClient1HasData) {
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";

  AutoFillProfiles expected_profiles;
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(MARION, expected_profiles[0]);
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(HOMER, expected_profiles[1]);
  AddProfile(GetPersonalDataManager(0), *expected_profiles[0]);
  AddProfile(GetPersonalDataManager(0), *expected_profiles[1]);

  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  ASSERT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients()));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));
  STLDeleteElements(&expected_profiles);
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest,
                       ProfileSameLabelOnDifferentClients) {
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";

  AutoFillProfiles profiles1;
  profiles1.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(HOMER, profiles1[0]);

  AutoFillProfiles profiles2;
  profiles2.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(MARION, profiles2[0]);
  profiles2[0]->set_label(ASCIIToUTF16("Shipping"));

  AddProfile(GetPersonalDataManager(0), *profiles1[0]);
  AddProfile(GetPersonalDataManager(1), *profiles2[0]);

  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  ASSERT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients()));

  // Since client1 associates first, client2's "Shipping" profile will
  // be overwritten by the one stored in the cloud by profile1.
  EXPECT_TRUE(CompareAutoFillProfiles(profiles1,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(profiles1,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));
  STLDeleteElements(&profiles1);
  STLDeleteElements(&profiles2);
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest,
                       ProfileSameLabelOnClient1) {
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";

  AutoFillProfiles expected_profiles;
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(HOMER, expected_profiles[0]);
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(HOMER, expected_profiles[1]);

  AddProfile(GetPersonalDataManager(0), *expected_profiles[0]);
  AddProfile(GetPersonalDataManager(0), *expected_profiles[1]);

  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  ASSERT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients()));

  // One of the duplicate profiles will have its label renamed to
  // "Shipping2".
  expected_profiles[0]->set_label(ASCIIToUTF16("Shipping2"));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));
  STLDeleteElements(&expected_profiles);
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest, ProfileSteady) {
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";

  // Client0 adds a profile.
  AutoFillProfiles expected_profiles;
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(HOMER, expected_profiles[0]);
  AddProfile(GetPersonalDataManager(0), *expected_profiles[0]);
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));

  // Client1 adds a profile.
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(MARION, expected_profiles[1]);
  AddProfile(GetPersonalDataManager(1), *expected_profiles[1]);
  EXPECT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0)));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));

  // Client0 adds a conflicting profile.
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(MARION, expected_profiles[2]);
  AddProfile(GetPersonalDataManager(0), *expected_profiles[2]);
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  // The conflicting profile's label will be made unique.
  expected_profiles[2]->set_label(ASCIIToUTF16("Billing2"));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));

  // Client1 removes a profile.
  delete expected_profiles.front();
  expected_profiles.erase(expected_profiles.begin());
  RemoveProfile(GetPersonalDataManager(1), ASCIIToUTF16("Shipping"));
  EXPECT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0)));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));

  // Client0 updates a profile.
  expected_profiles[0]->SetInfo(AutoFillType(NAME_FIRST),
                                ASCIIToUTF16("Bart"));
  UpdateProfile(GetPersonalDataManager(0),
                ASCIIToUTF16("Billing"),
                AutoFillType(NAME_FIRST),
                ASCIIToUTF16("Bart"));
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));

  // Client1 removes everything.
  STLDeleteElements(&expected_profiles);
  RemoveProfile(GetPersonalDataManager(1), ASCIIToUTF16("Billing"));
  RemoveProfile(GetPersonalDataManager(1), ASCIIToUTF16("Billing2"));
  EXPECT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0)));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));
}
<commit_msg>Marking Client1HasData test as failed due to bug 51956.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/utf_string_conversions.h"
#include "chrome/test/live_sync/live_autofill_sync_test.h"

// TODO(rsimha): Remove FAILS prefix after crbug.com/51956 is fixed.
IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest,
                       FAILS_Client1HasData) {
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";

  AutofillKeys keys;
  keys.insert(AutofillKey("name0", "value0"));
  keys.insert(AutofillKey("name0", "value1"));
  keys.insert(AutofillKey("name1", "value2"));
  keys.insert(AutofillKey(WideToUTF16(L"Sigur R\u00F3s"),
                          WideToUTF16(L"\u00C1g\u00E6tis byrjun")));
  AddFormFieldsToWebData(GetWebDataService(0), keys);

  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  ASSERT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients()));

  AutofillKeys wd1_keys;
  GetAllAutofillKeys(GetWebDataService(1), &wd1_keys);
  EXPECT_EQ(keys, wd1_keys);
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest, BothHaveData) {
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";

  AutofillKeys keys1;
  keys1.insert(AutofillKey("name0", "value0"));
  keys1.insert(AutofillKey("name0", "value1"));
  keys1.insert(AutofillKey("name1", "value2"));
  AddFormFieldsToWebData(GetWebDataService(0), keys1);

  AutofillKeys keys2;
  keys2.insert(AutofillKey("name0", "value1"));
  keys2.insert(AutofillKey("name1", "value2"));
  keys2.insert(AutofillKey("name2", "value3"));
  keys2.insert(AutofillKey("name3", "value3"));
  AddFormFieldsToWebData(GetWebDataService(1), keys2);

  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  EXPECT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients()));

  AutofillKeys expected_keys;
  expected_keys.insert(AutofillKey("name0", "value0"));
  expected_keys.insert(AutofillKey("name0", "value1"));
  expected_keys.insert(AutofillKey("name1", "value2"));
  expected_keys.insert(AutofillKey("name2", "value3"));
  expected_keys.insert(AutofillKey("name3", "value3"));

  AutofillKeys wd0_keys;
  GetAllAutofillKeys(GetWebDataService(0), &wd0_keys);
  EXPECT_EQ(expected_keys, wd0_keys);

  AutofillKeys wd1_keys;
  GetAllAutofillKeys(GetWebDataService(1), &wd1_keys);
  EXPECT_EQ(expected_keys, wd1_keys);
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest, Steady) {
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";

  // Client0 adds a key.
  AutofillKeys add_one_key;
  add_one_key.insert(AutofillKey("name0", "value0"));
  AddFormFieldsToWebData(GetWebDataService(0), add_one_key);
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  AutofillKeys expected_keys;
  expected_keys.insert(AutofillKey("name0", "value0"));

  AutofillKeys keys;
  GetAllAutofillKeys(GetWebDataService(0), &keys);
  EXPECT_EQ(expected_keys, keys);
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(1), &keys);
  EXPECT_EQ(expected_keys, keys);

  // Client1 adds a key.
  add_one_key.clear();
  add_one_key.insert(AutofillKey("name1", "value1"));
  AddFormFieldsToWebData(GetWebDataService(1), add_one_key);
  EXPECT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0)));

  expected_keys.insert(AutofillKey("name1", "value1"));
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(0), &keys);
  EXPECT_EQ(expected_keys, keys);
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(1), &keys);
  EXPECT_EQ(expected_keys, keys);

  // Client0 adds a key with the same name.
  add_one_key.clear();
  add_one_key.insert(AutofillKey("name1", "value2"));
  AddFormFieldsToWebData(GetWebDataService(0), add_one_key);
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  expected_keys.insert(AutofillKey("name1", "value2"));
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(0), &keys);
  EXPECT_EQ(expected_keys, keys);
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(1), &keys);
  EXPECT_EQ(expected_keys, keys);

  // Client1 removes a key.
  RemoveKeyFromWebData(GetWebDataService(1), AutofillKey("name1", "value1"));
  EXPECT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0)));

  expected_keys.erase(AutofillKey("name1", "value1"));
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(0), &keys);
  EXPECT_EQ(expected_keys, keys);
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(1), &keys);
  EXPECT_EQ(expected_keys, keys);

  // Client0 removes the rest.
  RemoveKeyFromWebData(GetWebDataService(0), AutofillKey("name0", "value0"));
  RemoveKeyFromWebData(GetWebDataService(0), AutofillKey("name1", "value2"));
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  keys.clear();
  GetAllAutofillKeys(GetWebDataService(0), &keys);
  EXPECT_EQ(0U, keys.size());
  keys.clear();
  GetAllAutofillKeys(GetWebDataService(1), &keys);
  EXPECT_EQ(0U, keys.size());
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest, ProfileClient1HasData) {
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";

  AutoFillProfiles expected_profiles;
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(MARION, expected_profiles[0]);
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(HOMER, expected_profiles[1]);
  AddProfile(GetPersonalDataManager(0), *expected_profiles[0]);
  AddProfile(GetPersonalDataManager(0), *expected_profiles[1]);

  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  ASSERT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients()));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));
  STLDeleteElements(&expected_profiles);
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest,
                       ProfileSameLabelOnDifferentClients) {
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";

  AutoFillProfiles profiles1;
  profiles1.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(HOMER, profiles1[0]);

  AutoFillProfiles profiles2;
  profiles2.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(MARION, profiles2[0]);
  profiles2[0]->set_label(ASCIIToUTF16("Shipping"));

  AddProfile(GetPersonalDataManager(0), *profiles1[0]);
  AddProfile(GetPersonalDataManager(1), *profiles2[0]);

  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  ASSERT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients()));

  // Since client1 associates first, client2's "Shipping" profile will
  // be overwritten by the one stored in the cloud by profile1.
  EXPECT_TRUE(CompareAutoFillProfiles(profiles1,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(profiles1,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));
  STLDeleteElements(&profiles1);
  STLDeleteElements(&profiles2);
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest,
                       ProfileSameLabelOnClient1) {
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";

  AutoFillProfiles expected_profiles;
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(HOMER, expected_profiles[0]);
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(HOMER, expected_profiles[1]);

  AddProfile(GetPersonalDataManager(0), *expected_profiles[0]);
  AddProfile(GetPersonalDataManager(0), *expected_profiles[1]);

  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  ASSERT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients()));

  // One of the duplicate profiles will have its label renamed to
  // "Shipping2".
  expected_profiles[0]->set_label(ASCIIToUTF16("Shipping2"));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));
  STLDeleteElements(&expected_profiles);
}

IN_PROC_BROWSER_TEST_F(TwoClientLiveAutofillSyncTest, ProfileSteady) {
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";

  // Client0 adds a profile.
  AutoFillProfiles expected_profiles;
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(HOMER, expected_profiles[0]);
  AddProfile(GetPersonalDataManager(0), *expected_profiles[0]);
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));

  // Client1 adds a profile.
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(MARION, expected_profiles[1]);
  AddProfile(GetPersonalDataManager(1), *expected_profiles[1]);
  EXPECT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0)));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));

  // Client0 adds a conflicting profile.
  expected_profiles.push_back(new AutoFillProfile(string16(), 0));
  FillProfile(MARION, expected_profiles[2]);
  AddProfile(GetPersonalDataManager(0), *expected_profiles[2]);
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  // The conflicting profile's label will be made unique.
  expected_profiles[2]->set_label(ASCIIToUTF16("Billing2"));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));

  // Client1 removes a profile.
  delete expected_profiles.front();
  expected_profiles.erase(expected_profiles.begin());
  RemoveProfile(GetPersonalDataManager(1), ASCIIToUTF16("Shipping"));
  EXPECT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0)));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));

  // Client0 updates a profile.
  expected_profiles[0]->SetInfo(AutoFillType(NAME_FIRST),
                                ASCIIToUTF16("Bart"));
  UpdateProfile(GetPersonalDataManager(0),
                ASCIIToUTF16("Billing"),
                AutoFillType(NAME_FIRST),
                ASCIIToUTF16("Bart"));
  EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));

  // Client1 removes everything.
  STLDeleteElements(&expected_profiles);
  RemoveProfile(GetPersonalDataManager(1), ASCIIToUTF16("Billing"));
  RemoveProfile(GetPersonalDataManager(1), ASCIIToUTF16("Billing2"));
  EXPECT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0)));

  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(0))));
  EXPECT_TRUE(CompareAutoFillProfiles(expected_profiles,
      GetAllAutoFillProfiles(GetPersonalDataManager(1))));
}
<|endoftext|>