/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ //============================================================================= // // Memory utils and algorithms // //============================================================================= #ifndef AGS_SHARED_UTIL_MEMORY_H #define AGS_SHARED_UTIL_MEMORY_H //include #include "ags/shared/util/bbop.h" #include "ags/shared/util/math.h" namespace AGS3 { #if defined (AGS_STRICT_ALIGNMENT) || defined (TEST_STRICT_ALIGNMENT) #define MEMORY_STRICT_ALIGNMENT #endif namespace AGS { namespace Shared { namespace Memory { //------------------------------------------------------------------------- // Converts pointer to 32-bit integer value and vice-versa. // Only for use in special cases for compatibility with 32-bit plugin API. // Dangerous on 64-bit systems. //------------------------------------------------------------------------- template inline int32_t PtrToInt32(T *ptr) { return static_cast(reinterpret_cast(ptr)); } template inline T *Int32ToPtr(int32_t value) { return reinterpret_cast(static_cast(value)); } //------------------------------------------------------------------------- // Functions for reading and writing basic types from/to the memory. // Implement safety workaround for CPUs with alignment restrictions // (e.g. MIPS). //------------------------------------------------------------------------- inline int16_t ReadInt16(const void *ptr) { #if defined (MEMORY_STRICT_ALIGNMENT) const uint8_t *b = (const uint8_t *)ptr; #if defined (BITBYTE_BIG_ENDIAN) return (b[0] << 8) | b[1]; #else return (b[1] << 8) | b[0]; #endif #else return *(const int16_t *)ptr; #endif } inline int32_t ReadInt32(const void *ptr) { #if defined (MEMORY_STRICT_ALIGNMENT) const uint8_t *b = (const uint8_t *)ptr; #if defined (BITBYTE_BIG_ENDIAN) return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; #else return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]; #endif #else return *(const int32_t *)ptr; #endif } inline int64_t ReadInt64(const void *ptr) { #if defined (MEMORY_STRICT_ALIGNMENT) const uint8_t *b = (const uint8_t *)ptr; #if defined (BITBYTE_BIG_ENDIAN) return ((uint64_t)b[0] << 56) | ((uint64_t)b[1] << 48) | ((uint64_t)b[2] << 40) | ((uint64_t)b[3] << 32) | (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7]; #else return ((uint64_t)b[7] << 56) | ((uint64_t)b[6] << 48) | ((uint64_t)b[5] << 40) | ((uint64_t)b[4] << 32) | (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]; #endif #else return *(const int64_t *)ptr; #endif } inline void WriteInt16(void *ptr, int16_t value) { #if defined (MEMORY_STRICT_ALIGNMENT) uint8_t *b = (uint8_t *)ptr; #if defined (BITBYTE_BIG_ENDIAN) b[0] = (uint8_t)(value >> 8); b[1] = (uint8_t)(value); #else b[1] = (uint8_t)(value >> 8); b[0] = (uint8_t)(value); #endif #else *(int16_t *)ptr = value; #endif } inline void WriteInt32(void *ptr, int32_t value) { #if defined (MEMORY_STRICT_ALIGNMENT) uint8_t *b = (uint8_t *)ptr; #if defined (BITBYTE_BIG_ENDIAN) b[0] = (uint8_t)(value >> 24); b[1] = (uint8_t)(value >> 16); b[2] = (uint8_t)(value >> 8); b[3] = (uint8_t)(value); #else b[3] = (uint8_t)(value >> 24); b[2] = (uint8_t)(value >> 16); b[1] = (uint8_t)(value >> 8); b[0] = (uint8_t)(value); #endif #else *(int32_t *)ptr = value; #endif } inline void WriteInt64(void *ptr, int64_t value) { #if defined (MEMORY_STRICT_ALIGNMENT) uint8_t *b = (uint8_t *)ptr; #if defined (BITBYTE_BIG_ENDIAN) b[0] = (uint8_t)(value >> 56); b[1] = (uint8_t)(value >> 48); b[2] = (uint8_t)(value >> 40); b[3] = (uint8_t)(value >> 32); b[4] = (uint8_t)(value >> 24); b[5] = (uint8_t)(value >> 16); b[6] = (uint8_t)(value >> 8); b[7] = (uint8_t)(value); #else b[7] = (uint8_t)(value >> 56); b[6] = (uint8_t)(value >> 48); b[5] = (uint8_t)(value >> 40); b[4] = (uint8_t)(value >> 32); b[3] = (uint8_t)(value >> 24); b[2] = (uint8_t)(value >> 16); b[1] = (uint8_t)(value >> 8); b[0] = (uint8_t)(value); #endif #else *(int64_t *)ptr = value; #endif } //------------------------------------------------------------------------- // Helpers for reading and writing from memory with respect for endianess. //------------------------------------------------------------------------- inline int16_t ReadInt16LE(const void *ptr) { return BBOp::Int16FromLE(ReadInt16(ptr)); } inline int32_t ReadInt32LE(const void *ptr) { return BBOp::Int32FromLE(ReadInt32(ptr)); } inline int64_t ReadInt64LE(const void *ptr) { return BBOp::Int64FromLE(ReadInt64(ptr)); } inline void WriteInt16LE(void *ptr, int16_t value) { WriteInt16(ptr, BBOp::Int16FromLE(value)); } inline void WriteInt32LE(void *ptr, int32_t value) { WriteInt32(ptr, BBOp::Int32FromLE(value)); } inline void WriteInt64LE(void *ptr, int64_t value) { WriteInt64(ptr, BBOp::Int64FromLE(value)); } inline int16_t ReadInt16BE(const void *ptr) { return BBOp::Int16FromBE(ReadInt16(ptr)); } inline int32_t ReadInt32BE(const void *ptr) { return BBOp::Int32FromBE(ReadInt32(ptr)); } inline int64_t ReadInt64BE(const void *ptr) { return BBOp::Int64FromBE(ReadInt64(ptr)); } inline void WriteInt16BE(void *ptr, int16_t value) { WriteInt16(ptr, BBOp::Int16FromBE(value)); } inline void WriteInt32BE(void *ptr, int32_t value) { WriteInt32(ptr, BBOp::Int32FromBE(value)); } inline void WriteInt64BE(void *ptr, int64_t value) { WriteInt64(ptr, BBOp::Int64FromBE(value)); } //------------------------------------------------------------------------- // Memory data manipulation //------------------------------------------------------------------------- // Copies block of 2d data from source into destination. inline void BlockCopy(uint8_t *dst, const size_t dst_pitch, const size_t dst_offset, const uint8_t *src, const size_t src_pitch, const size_t src_offset, const size_t height) { for (size_t y = 0; y < height; ++y, src += src_pitch, dst += dst_pitch) memcpy(dst + dst_offset, src + src_offset, MIN(dst_pitch - dst_offset, src_pitch - src_offset)); } } // namespace Memory } // namespace Shared } // namespace AGS } // namespace AGS3 #endif