/**
 * Helper functions to open a stream given a file path
 */
nsresult sbOpenInputStream(nsAString const & aPath, nsIInputStream ** aStream)
{
  NS_ENSURE_ARG_POINTER(aStream);

  nsresult rv;
  nsCOMPtr<nsILocalFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = file->InitWithPath(aPath);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = sbOpenInputStream(file, aStream);
  NS_ENSURE_SUCCESS(rv, rv);

  return NS_OK;
}
nsresult sbOpenInputStream(nsIURI * aURI, nsIInputStream ** aStream)
{
  NS_ENSURE_ARG_POINTER(aStream);
  NS_ENSURE_ARG_POINTER(aURI);

  nsresult rv;
  nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIFile> file;
  rv = fileURL->GetFile(getter_AddRefs(file));
  NS_ENSURE_SUCCESS(rv, rv);

  rv = sbOpenInputStream(file, aStream);
  NS_ENSURE_SUCCESS(rv, rv);

  return NS_OK;
}
nsresult sbReadFile(nsIFile * aFile, nsACString &aBuffer)
{
  NS_ENSURE_ARG_POINTER(aFile);

  nsresult rv;
  PRInt64 fileSize;
  rv = aFile->GetFileSize(&fileSize);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIInputStream> stream;
  rv = sbOpenInputStream(aFile, getter_AddRefs(stream));
  NS_ENSURE_SUCCESS(rv, rv);

  rv = sbConsumeStream(stream, static_cast<PRUint32>(fileSize), aBuffer);
  NS_ENSURE_SUCCESS(rv, rv);

  return NS_OK;
}
nsresult sbDeviceXMLInfo::Read(nsIFile *          aDeviceXMLInfoFile,
                               const nsAString &  aExtensionsList)
{
  NS_ENSURE_ARG_POINTER(aDeviceXMLInfoFile);

  nsresult rv;

  nsString path;
  rv = aDeviceXMLInfoFile->GetPath(path);
  if (NS_FAILED(rv)) {
    path = NS_LITERAL_STRING("Unknown path");
  }

  // If aDeviceXMLInfoFile is a directory, scan it recursively for
  // device XML info files:
  bool isDir = PR_FALSE;
  rv = aDeviceXMLInfoFile->IsDirectory(&isDir);
  NS_ENSURE_SUCCESS(rv, rv);
  if (isDir) {
    Log("Searching directory %s",
        NS_LossyConvertUTF16toASCII(path).BeginReading());
    // aExtensionsList is a space-delimited list of extensions
    // (e.g., "ex1 ex2 ex3").  Trim any surrounding spaces and
    // don't scan the directory if the result is empty:
    nsString acceptExts(aExtensionsList);
    acceptExts.Trim(" ");
    Log("Extension List: %s",
        NS_LossyConvertUTF16toASCII(acceptExts).BeginReading());
    if (acceptExts.IsEmpty()) {
      return NS_OK;
    }

    // Normalize the extensions list for the comparison logic below.
    // That is, lower case with spaces before the first extension and
    // after the last:
    ToLowerCase(acceptExts);
    acceptExts.Insert(' ', 0);
    acceptExts.Append(' ');

    // Prepare to recursively enumerate all files in the directory:
    nsCOMPtr<sbIDirectoryEnumerator> scanner =
      do_CreateInstance(SB_DIRECTORYENUMERATOR_CONTRACTID, &rv);
    NS_ENSURE_SUCCESS(rv, rv);

    rv = scanner->SetFilesOnly(PR_TRUE);
    NS_ENSURE_SUCCESS(rv, rv);
    rv = scanner->Enumerate(aDeviceXMLInfoFile);
    NS_ENSURE_SUCCESS(rv, rv);

    // Enumerate files and filter by extension:
    bool more = PR_FALSE;
    while(NS_SUCCEEDED(rv = scanner->HasMoreElements(&more)) && more)
    {
      // Get the next file:
      nsCOMPtr<nsIFile> child;
      rv = scanner->GetNext(getter_AddRefs(child));
      NS_ENSURE_SUCCESS(rv, rv);

      // Get its extension and normalize it for comparison:
      nsString extension;
      rv = child->GetLeafName(extension);
      NS_ENSURE_SUCCESS(rv, rv);
      extension.Cut(0, extension.RFindChar('.') + 1);
      ToLowerCase(extension);
      extension.Insert(' ', 0);
      extension.Append(' ');

      // Read the file if its extension is on the accept list.
      // Warn about errors, but keep looping:
      if (acceptExts.Find(extension) != -1) {
        rv = Read(child, aExtensionsList);
        NS_WARN_IF_FALSE(
          NS_SUCCEEDED(rv),
          "Could not read device XML info from file in search directory");
      }
    }
    NS_ENSURE_SUCCESS(rv, rv);
    return NS_OK;
  }

  // Open a stream to parse:
  nsCOMPtr<nsIInputStream> inputStream;
  rv = sbOpenInputStream(aDeviceXMLInfoFile, getter_AddRefs(inputStream));
  NS_ENSURE_SUCCESS(rv, rv);

  Log("Parsing file %s",
      NS_LossyConvertUTF16toASCII(path).BeginReading());
  // Parse the stream and close it:
  rv = Read(inputStream);
  inputStream->Close();
  NS_ENSURE_SUCCESS(rv, rv);

  return NS_OK;
}