//===-- CFCString.cpp -------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "CFCString.h"
#include <string>
#include <glob.h>

//----------------------------------------------------------------------
// CFCString constructor
//----------------------------------------------------------------------
CFCString::CFCString(CFStringRef s) :
    CFCReleaser<CFStringRef> (s)
{
}

//----------------------------------------------------------------------
// CFCString copy constructor
//----------------------------------------------------------------------
CFCString::CFCString(const CFCString& rhs) :
    CFCReleaser<CFStringRef> (rhs)
{

}

//----------------------------------------------------------------------
// CFCString copy constructor
//----------------------------------------------------------------------
CFCString&
CFCString::operator=(const CFCString& rhs)
{
    if (this != &rhs)
        *this = rhs;
    return *this;
}

CFCString::CFCString (const char *cstr, CFStringEncoding cstr_encoding) :
    CFCReleaser<CFStringRef> ()
{
    if (cstr && cstr[0])
    {
        reset(::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding));
    }
}

//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
CFCString::~CFCString()
{
}

const char *
CFCString::GetFileSystemRepresentation(std::string& s)
{
    return CFCString::FileSystemRepresentation(get(), s);
}

CFStringRef
CFCString::SetFileSystemRepresentation (const char *path)
{
    CFStringRef new_value = NULL;
    if (path && path[0])
        new_value = ::CFStringCreateWithFileSystemRepresentation (kCFAllocatorDefault, path);
    reset(new_value);
    return get();
}


CFStringRef
CFCString::SetFileSystemRepresentationFromCFType (CFTypeRef cf_type)
{
    CFStringRef new_value = NULL;
    if (cf_type != NULL)
    {
        CFTypeID cf_type_id = ::CFGetTypeID(cf_type);

        if (cf_type_id == ::CFStringGetTypeID())
        {
            // Retain since we are using the existing object
            new_value = (CFStringRef)::CFRetain(cf_type);
        }
        else if (cf_type_id == ::CFURLGetTypeID())
        {
            new_value = ::CFURLCopyFileSystemPath((CFURLRef)cf_type, kCFURLPOSIXPathStyle);
        }
    }
    reset(new_value);
    return get();
}

CFStringRef
CFCString::SetFileSystemRepresentationAndExpandTilde (const char *path)
{
    std::string expanded_path;
    if (CFCString::ExpandTildeInPath(path, expanded_path))
        SetFileSystemRepresentation(expanded_path.c_str());
    else
        reset();
    return get();
}

const char *
CFCString::UTF8(std::string& str)
{
    return CFCString::UTF8(get(), str);
}

// Static function that puts a copy of the UTF8 contents of CF_STR into STR
// and returns the C string pointer that is contained in STR when successful, else
// NULL is returned. This allows the std::string parameter to own the extracted string,
// and also allows that string to be returned as a C string pointer that can be used.

const char *
CFCString::UTF8 (CFStringRef cf_str, std::string& str)
{
    if (cf_str)
    {
        const CFStringEncoding encoding = kCFStringEncodingUTF8;
        CFIndex max_utf8_str_len = CFStringGetLength (cf_str);
        max_utf8_str_len = CFStringGetMaximumSizeForEncoding (max_utf8_str_len, encoding);
        if (max_utf8_str_len > 0)
        {
            str.resize(max_utf8_str_len);
            if (!str.empty())
            {
                if (CFStringGetCString (cf_str, &str[0], str.size(), encoding))
                {
                    str.resize(strlen(str.c_str()));
                    return str.c_str();
                }
            }
        }
    }
    return NULL;
}

const char*
CFCString::ExpandTildeInPath(const char* path, std::string &expanded_path)
{
    glob_t globbuf;
    if (::glob (path, GLOB_TILDE, NULL, &globbuf) == 0)
    {
        expanded_path = globbuf.gl_pathv[0];
        ::globfree (&globbuf);
    }
    else
        expanded_path.clear();

    return expanded_path.c_str();
}

// Static function that puts a copy of the file system representation of CF_STR
// into STR and returns the C string pointer that is contained in STR when
// successful, else NULL is returned. This allows the std::string parameter
// to own the extracted string, and also allows that string to be returned as
// a C string pointer that can be used.

const char *
CFCString::FileSystemRepresentation (CFStringRef cf_str, std::string& str)
{
    if (cf_str)
    {
        CFIndex max_length = ::CFStringGetMaximumSizeOfFileSystemRepresentation (cf_str);
        if (max_length > 0)
        {
            str.resize(max_length);
            if (!str.empty())
            {
                if (::CFStringGetFileSystemRepresentation (cf_str, &str[0], str.size()))
                {
                    str.erase(::strlen(str.c_str()));
                    return str.c_str();
                }
            }
        }
    }
    str.erase();
    return NULL;
}


CFIndex
CFCString::GetLength() const
{
    CFStringRef str = get();
    if (str)
        return CFStringGetLength (str);
    return 0;
}
