//
//  TKEndianUtilities.m
//  ThemeKit
//
//  Created by Colin Cornaby on 11/4/06.
//  Copyright 2006 __MyCompanyName__. All rights reserved.
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#import "TKEndianUtilities.h"

//This function will resolve an endinanness given to it
//to the current platform. For example, passing it kNativeEndian
//on the Intel platform will return kLittleEndian.
TKEndianness resolveEndianness(TKEndianness endianness)
{
	if (endianness==kNativeEndian) {
		#ifdef __BIG_ENDIAN__
			return kBigEndian;
		#endif
		#ifdef __LITTLE_ENDIAN__
			return kLittleEndian;
		#endif
	}
	return endianness;
}

unsigned short swapShort(short x, TKEndianness fromPlatform, TKEndianness toPlatform)
{
	if(resolveEndianness(fromPlatform)==resolveEndianness(toPlatform))
		return x;
	if(toPlatform==kNativeEndian){
		if(fromPlatform == kBigEndian)
			return NSSwapBigShortToHost(x);
		if(fromPlatform == kLittleEndian)
			return NSSwapLittleShortToHost(x);
	}
	if(toPlatform==kBigEndian){
		if(fromPlatform == kBigEndian)
			return (x);
		if(fromPlatform == kLittleEndian)
			return NSSwapShort(x);
	}
	if(toPlatform==kLittleEndian){
		if(fromPlatform == kBigEndian)
			return NSSwapShort(x);
		if(fromPlatform == kLittleEndian)
			return x;
	}
	return -1;
}

//The following is an slightly edited version of Jason Harris's code
//for dealing with Endn resources
//http://www.geekspiff.com/themeEndianness/

ThemeDataError ThemeDataFormatForResourceFile(SInt16 inRefNum, 
                               TKEndianness *outFormat)
{
    SInt16          oldRefNum;
    Handle          theResource;
    ThemeDataError  result = kThemeDataNoError;
    
    if ( -1 == inRefNum || ! outFormat ) return kThemeDataBadParameter;
    
    oldRefNum = CurResFile();
    UseResFile(inRefNum);
    theResource = Get1Resource('Endn', 128);
    if ( theResource )
    {
        HLock(theResource);
        ThemeEndianness *endn = (ThemeEndianness *)*theResource;
        endn->version = CFSwapInt32BigToHost(endn->version);
        endn->isLittleEndian = CFSwapInt32BigToHost(endn->isLittleEndian);
        if ( 0 == endn->version )
        {
            if ( endn->isLittleEndian )
                *outFormat = kLittleEndian;
            else
                *outFormat = kBigEndian;
        }
        else
        {
            *outFormat = kUnknownEndian;
            result = kThemeDataBadResource;
        }
        ReleaseResource(theResource);
    }
    else
        *outFormat = kBigEndian;
    
    UseResFile(oldRefNum);
    return result;
}


ThemeDataError 
SetThemeDataFormatForResourceFile(SInt16 inRefNum, 
                                  TKEndianness inFormat)
{
    SInt16          oldRefNum;
    Handle          endnHandle, newResource = NULL;
    ThemeDataError  result = kThemeDataUnexpectedError;
    
    if ( -1 == inRefNum || kUnknownEndian == inFormat ) return kThemeDataBadParameter;
    
	inFormat = resolveEndianness(inFormat);
	
    oldRefNum = CurResFile();
    UseResFile(inRefNum);
    
    endnHandle = NewHandle(sizeof(ThemeEndianness));
    if ( ! endnHandle ) goto DONE;
    HLock(endnHandle);
    ThemeEndianness *endn = (ThemeEndianness *)*endnHandle;
    endn->version = CFSwapInt32HostToBig(0);
    endn->isLittleEndian = CFSwapInt32HostToBig((kLittleEndian == inFormat) ? 1 : 0);
    
    // if this resource is already in the file, delete it
    SetResLoad(false);
    result = kThemeDataBadResource;
    Handle oldResource = Get1Resource('Endn', 128);
    if ( oldResource )
    {
        RemoveResource(oldResource);
        if ( noErr != ResError() )
            goto DONE;
        DisposeHandle(oldResource);
    }
    SetResLoad(true);
    
    // add in the new resource data
    AddResource( endnHandle, 'Endn', 128, "\p" );
    if( noErr != ResError() ) goto DONE;
    newResource = endnHandle;
    endnHandle = NULL;
    ChangedResource(newResource);
    if( noErr != ResError() ) goto DONE;
    WriteResource(newResource);
    if( noErr != ResError() ) goto DONE;
    result = kThemeDataNoError;
    
DONE:
    if ( endnHandle )
        DisposeHandle(endnHandle);
    if ( newResource )
        ReleaseResource(newResource);
    UseResFile(oldRefNum);
    return result;
}