mirror of
https://github.com/OpenEmu/PCSX2-Core.git
synced 2025-11-01 11:07:36 +00:00
Merge pull request #1 from MaddTheSane/upstream-pcsx2
Implement PCSX2. Thanks to @duckey77 for making sure it runs.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
.DS_Store
|
||||
*.xcuserdata/
|
||||
xcuserdata/
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "pcsx2"]
|
||||
path = pcsx2
|
||||
url = https://github.com/tellowkrinkle/pcsx2.git
|
||||
@@ -0,0 +1,855 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "SPU2/Global.h"
|
||||
|
||||
#include "OESndOut.h"
|
||||
|
||||
void ADMAOutLogWrite(void* lpData, u32 ulSize);
|
||||
|
||||
#include "SPU2/interpolate_table.h"
|
||||
|
||||
static const s32 tbl_XA_Factor[16][2] =
|
||||
{
|
||||
{0, 0},
|
||||
{60, 0},
|
||||
{115, -52},
|
||||
{98, -55},
|
||||
{122, -60}};
|
||||
|
||||
|
||||
// Performs a 64-bit multiplication between two values and returns the
|
||||
// high 32 bits as a result (discarding the fractional 32 bits).
|
||||
// The combined fractional bits of both inputs must be 32 bits for this
|
||||
// to work properly.
|
||||
//
|
||||
// This is meant to be a drop-in replacement for times when the 'div' part
|
||||
// of a MulDiv is a constant. (example: 1<<8, or 4096, etc)
|
||||
//
|
||||
// [Air] Performance breakdown: This is over 10 times faster than MulDiv in
|
||||
// a *worst case* scenario. It's also more accurate since it forces the
|
||||
// caller to extend the inputs so that they make use of all 32 bits of
|
||||
// precision.
|
||||
//
|
||||
static __forceinline s32 MulShr32(s32 srcval, s32 mulval)
|
||||
{
|
||||
return (s64)srcval * mulval >> 32;
|
||||
}
|
||||
|
||||
__forceinline s32 clamp_mix(s32 x, u8 bitshift)
|
||||
{
|
||||
assert(bitshift <= 15);
|
||||
return GetClamped(x, -(0x8000 << bitshift), 0x7fff << bitshift);
|
||||
}
|
||||
|
||||
#if _MSC_VER
|
||||
__forceinline
|
||||
// Without the keyword static, gcc compilation fails on the inlining...
|
||||
// Unfortunately the function is also used in Reverb.cpp. In order to keep the code
|
||||
// clean we just disable it.
|
||||
// We will need link-time code generation / Whole Program optimization to do a clean
|
||||
// inline. Gcc 4.5 has the experimental options -flto, -fwhopr and -fwhole-program to
|
||||
// do it but it still experimental...
|
||||
#endif
|
||||
StereoOut32
|
||||
clamp_mix(const StereoOut32& sample, u8 bitshift)
|
||||
{
|
||||
// We should clampify between -0x8000 and 0x7fff, however some audio output
|
||||
// modules or sound drivers could (will :p) overshoot with that. So giving it a small safety.
|
||||
|
||||
return StereoOut32(
|
||||
GetClamped(sample.Left, -(0x7f00 << bitshift), 0x7f00 << bitshift),
|
||||
GetClamped(sample.Right, -(0x7f00 << bitshift), 0x7f00 << bitshift));
|
||||
}
|
||||
|
||||
static void __forceinline XA_decode_block(s16* buffer, const s16* block, s32& prev1, s32& prev2)
|
||||
{
|
||||
const s32 header = *block;
|
||||
const s32 shift = (header & 0xF) + 16;
|
||||
const int id = header >> 4 & 0xF;
|
||||
if (id > 4 && MsgToConsole())
|
||||
ConLog("* SPU2: Unknown ADPCM coefficients table id %d\n", id);
|
||||
const s32 pred1 = tbl_XA_Factor[id][0];
|
||||
const s32 pred2 = tbl_XA_Factor[id][1];
|
||||
|
||||
const s8* blockbytes = (s8*)&block[1];
|
||||
const s8* blockend = &blockbytes[13];
|
||||
|
||||
for (; blockbytes <= blockend; ++blockbytes)
|
||||
{
|
||||
s32 data = ((*blockbytes) << 28) & 0xF0000000;
|
||||
s32 pcm = (data >> shift) + (((pred1 * prev1) + (pred2 * prev2) + 32) >> 6);
|
||||
|
||||
Clampify(pcm, -0x8000, 0x7fff);
|
||||
*(buffer++) = pcm;
|
||||
|
||||
data = ((*blockbytes) << 24) & 0xF0000000;
|
||||
s32 pcm2 = (data >> shift) + (((pred1 * pcm) + (pred2 * prev1) + 32) >> 6);
|
||||
|
||||
Clampify(pcm2, -0x8000, 0x7fff);
|
||||
*(buffer++) = pcm2;
|
||||
|
||||
prev2 = pcm;
|
||||
prev1 = pcm2;
|
||||
}
|
||||
}
|
||||
|
||||
static void __forceinline IncrementNextA(V_Core& thiscore, uint voiceidx)
|
||||
{
|
||||
V_Voice& vc(thiscore.Voices[voiceidx]);
|
||||
|
||||
// Important! Both cores signal IRQ when an address is read, regardless of
|
||||
// which core actually reads the address.
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (Cores[i].IRQEnable && (vc.NextA == Cores[i].IRQA))
|
||||
{
|
||||
//if( IsDevBuild )
|
||||
// ConLog(" * SPU2 Core %d: IRQ Requested (IRQA (%05X) passed; voice %d).\n", i, Cores[i].IRQA, thiscore.Index * 24 + voiceidx);
|
||||
|
||||
SetIrqCall(i);
|
||||
}
|
||||
}
|
||||
|
||||
vc.NextA++;
|
||||
vc.NextA &= 0xFFFFF;
|
||||
}
|
||||
|
||||
// decoded pcm data, used to cache the decoded data so that it needn't be decoded
|
||||
// multiple times. Cache chunks are decoded when the mixer requests the blocks, and
|
||||
// invalided when DMA transfers and memory writes are performed.
|
||||
PcmCacheEntry* pcm_cache_data = nullptr;
|
||||
|
||||
int g_counter_cache_hits = 0;
|
||||
int g_counter_cache_misses = 0;
|
||||
int g_counter_cache_ignores = 0;
|
||||
|
||||
// LOOP/END sets the ENDX bit and sets NAX to LSA, and the voice is muted if LOOP is not set
|
||||
// LOOP seems to only have any effect on the block with LOOP/END set, where it prevents muting the voice
|
||||
// (the documented requirement that every block in a loop has the LOOP bit set is nonsense according to tests)
|
||||
// LOOP/START sets LSA to NAX unless LSA was written manually since sound generation started
|
||||
// (see LoopMode, the method by which this is achieved on the real SPU2 is unknown)
|
||||
#define XAFLAG_LOOP_END (1ul << 0)
|
||||
#define XAFLAG_LOOP (1ul << 1)
|
||||
#define XAFLAG_LOOP_START (1ul << 2)
|
||||
|
||||
static __forceinline s32 GetNextDataBuffered(V_Core& thiscore, uint voiceidx)
|
||||
{
|
||||
V_Voice& vc(thiscore.Voices[voiceidx]);
|
||||
|
||||
if ((vc.SCurrent & 3) == 0)
|
||||
{
|
||||
if (vc.PendingLoopStart)
|
||||
{
|
||||
if ((Cycles - vc.PlayCycle) >= 4)
|
||||
{
|
||||
if (vc.LoopCycle < vc.PlayCycle)
|
||||
{
|
||||
vc.LoopStartA = vc.PendingLoopStartA;
|
||||
ConLog("Core %d Voice %d Loop Written by HW within 4T of Key On, Now Applying\n", thiscore.Index, voiceidx);
|
||||
vc.LoopMode = 1;
|
||||
}
|
||||
else
|
||||
ConLog("Loop point from waveform set within 4T's, ignoring HW write\n");
|
||||
|
||||
vc.PendingLoopStart = false;
|
||||
}
|
||||
}
|
||||
IncrementNextA(thiscore, voiceidx);
|
||||
|
||||
if ((vc.NextA & 7) == 0) // vc.SCurrent == 24 equivalent
|
||||
{
|
||||
if (vc.LoopFlags & XAFLAG_LOOP_END)
|
||||
{
|
||||
thiscore.Regs.ENDX |= (1 << voiceidx);
|
||||
vc.NextA = vc.LoopStartA | 1;
|
||||
if (!(vc.LoopFlags & XAFLAG_LOOP))
|
||||
{
|
||||
vc.Stop();
|
||||
|
||||
if (IsDevBuild)
|
||||
{
|
||||
if (MsgVoiceOff())
|
||||
ConLog("* SPU2: Voice Off by EndPoint: %d \n", voiceidx);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
vc.NextA++; // no, don't IncrementNextA here. We haven't read the header yet.
|
||||
}
|
||||
}
|
||||
|
||||
if (vc.SCurrent == 28)
|
||||
{
|
||||
vc.SCurrent = 0;
|
||||
|
||||
// We'll need the loop flags and buffer pointers regardless of cache status:
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
if (Cores[i].IRQEnable && Cores[i].IRQA == (vc.NextA & 0xFFFF8))
|
||||
SetIrqCall(i);
|
||||
|
||||
s16* memptr = GetMemPtr(vc.NextA & 0xFFFF8);
|
||||
vc.LoopFlags = *memptr >> 8; // grab loop flags from the upper byte.
|
||||
|
||||
if ((vc.LoopFlags & XAFLAG_LOOP_START) && !vc.LoopMode)
|
||||
{
|
||||
vc.LoopStartA = vc.NextA & 0xFFFF8;
|
||||
vc.LoopCycle = Cycles;
|
||||
}
|
||||
|
||||
const int cacheIdx = vc.NextA / pcm_WordsPerBlock;
|
||||
PcmCacheEntry& cacheLine = pcm_cache_data[cacheIdx];
|
||||
vc.SBuffer = cacheLine.Sampledata;
|
||||
|
||||
if (cacheLine.Validated && vc.Prev1 == cacheLine.Prev1 && vc.Prev2 == cacheLine.Prev2)
|
||||
{
|
||||
// Cached block! Read from the cache directly.
|
||||
// Make sure to propagate the prev1/prev2 ADPCM:
|
||||
|
||||
vc.Prev1 = vc.SBuffer[27];
|
||||
vc.Prev2 = vc.SBuffer[26];
|
||||
|
||||
//ConLog( "* SPU2: Cache Hit! NextA=0x%x, cacheIdx=0x%x\n", vc.NextA, cacheIdx );
|
||||
|
||||
if (IsDevBuild)
|
||||
g_counter_cache_hits++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only flag the cache if it's a non-dynamic memory range.
|
||||
if (vc.NextA >= SPU2_DYN_MEMLINE)
|
||||
{
|
||||
cacheLine.Validated = true;
|
||||
cacheLine.Prev1 = vc.Prev1;
|
||||
cacheLine.Prev2 = vc.Prev2;
|
||||
}
|
||||
|
||||
if (IsDevBuild)
|
||||
{
|
||||
if (vc.NextA < SPU2_DYN_MEMLINE)
|
||||
g_counter_cache_ignores++;
|
||||
else
|
||||
g_counter_cache_misses++;
|
||||
}
|
||||
|
||||
XA_decode_block(vc.SBuffer, memptr, vc.Prev1, vc.Prev2);
|
||||
}
|
||||
}
|
||||
|
||||
return vc.SBuffer[vc.SCurrent++];
|
||||
}
|
||||
|
||||
static __forceinline void GetNextDataDummy(V_Core& thiscore, uint voiceidx)
|
||||
{
|
||||
V_Voice& vc(thiscore.Voices[voiceidx]);
|
||||
|
||||
IncrementNextA(thiscore, voiceidx);
|
||||
|
||||
if ((vc.NextA & 7) == 0) // vc.SCurrent == 24 equivalent
|
||||
{
|
||||
if (vc.LoopFlags & XAFLAG_LOOP_END)
|
||||
{
|
||||
thiscore.Regs.ENDX |= (1 << voiceidx);
|
||||
vc.NextA = vc.LoopStartA | 1;
|
||||
}
|
||||
else
|
||||
vc.NextA++; // no, don't IncrementNextA here. We haven't read the header yet.
|
||||
}
|
||||
|
||||
if (vc.SCurrent == 28)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
if (Cores[i].IRQEnable && Cores[i].IRQA == (vc.NextA & 0xFFFF8))
|
||||
SetIrqCall(i);
|
||||
|
||||
vc.LoopFlags = *GetMemPtr(vc.NextA & 0xFFFF8) >> 8; // grab loop flags from the upper byte.
|
||||
|
||||
if ((vc.LoopFlags & XAFLAG_LOOP_START) && !vc.LoopMode)
|
||||
vc.LoopStartA = vc.NextA & 0xFFFF8;
|
||||
|
||||
vc.SCurrent = 0;
|
||||
}
|
||||
|
||||
vc.SP -= 0x1000 * (4 - (vc.SCurrent & 3));
|
||||
vc.SCurrent += 4 - (vc.SCurrent & 3);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
|
||||
// Data is expected to be 16 bit signed (typical stuff!).
|
||||
// volume is expected to be 32 bit signed (31 bits with reverse phase)
|
||||
// Data is shifted up by 1 bit to give the output an effective 16 bit range.
|
||||
static __forceinline s32 ApplyVolume(s32 data, s32 volume)
|
||||
{
|
||||
//return (volume * data) >> 15;
|
||||
return MulShr32(data << 1, volume);
|
||||
}
|
||||
|
||||
static __forceinline StereoOut32 ApplyVolume(const StereoOut32& data, const V_VolumeLR& volume)
|
||||
{
|
||||
return StereoOut32(
|
||||
ApplyVolume(data.Left, volume.Left),
|
||||
ApplyVolume(data.Right, volume.Right));
|
||||
}
|
||||
|
||||
static __forceinline StereoOut32 ApplyVolume(const StereoOut32& data, const V_VolumeSlideLR& volume)
|
||||
{
|
||||
return StereoOut32(
|
||||
ApplyVolume(data.Left, volume.Left.Value),
|
||||
ApplyVolume(data.Right, volume.Right.Value));
|
||||
}
|
||||
|
||||
static void __forceinline UpdatePitch(uint coreidx, uint voiceidx)
|
||||
{
|
||||
V_Voice& vc(Cores[coreidx].Voices[voiceidx]);
|
||||
s32 pitch;
|
||||
|
||||
// [Air] : re-ordered comparisons: Modulated is much more likely to be zero than voice,
|
||||
// and so the way it was before it's have to check both voice and modulated values
|
||||
// most of the time. Now it'll just check Modulated and short-circuit past the voice
|
||||
// check (not that it amounts to much, but eh every little bit helps).
|
||||
if ((vc.Modulated == 0) || (voiceidx == 0))
|
||||
pitch = vc.Pitch;
|
||||
else
|
||||
pitch = GetClamped((vc.Pitch * (32768 + Cores[coreidx].Voices[voiceidx - 1].OutX)) >> 15, 0, 0x3fff);
|
||||
|
||||
vc.SP += pitch;
|
||||
}
|
||||
|
||||
|
||||
static __forceinline void CalculateADSR(V_Core& thiscore, uint voiceidx)
|
||||
{
|
||||
V_Voice& vc(thiscore.Voices[voiceidx]);
|
||||
|
||||
if (vc.ADSR.Phase == 0)
|
||||
{
|
||||
vc.ADSR.Value = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vc.ADSR.Calculate())
|
||||
{
|
||||
if (IsDevBuild)
|
||||
{
|
||||
if (MsgVoiceOff())
|
||||
ConLog("* SPU2: Voice Off by ADSR: %d \n", voiceidx);
|
||||
}
|
||||
vc.Stop();
|
||||
}
|
||||
|
||||
pxAssume(vc.ADSR.Value >= 0); // ADSR should never be negative...
|
||||
}
|
||||
|
||||
|
||||
__forceinline static s32 GaussianInterpolate(s32 pv4, s32 pv3, s32 pv2, s32 pv1, s32 i)
|
||||
{
|
||||
s32 out = 0;
|
||||
out = (interpTable[0x0FF - i] * pv4) >> 15;
|
||||
out += (interpTable[0x1FF - i] * pv3) >> 15;
|
||||
out += (interpTable[0x100 + i] * pv2) >> 15;
|
||||
out += (interpTable[0x000 + i] * pv1) >> 15;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
Tension: 65535 is high, 32768 is normal, 0 is low
|
||||
*/
|
||||
|
||||
template <s32 i_tension>
|
||||
__forceinline static s32 HermiteInterpolate(
|
||||
s32 y0, // 16.0
|
||||
s32 y1, // 16.0
|
||||
s32 y2, // 16.0
|
||||
s32 y3, // 16.0
|
||||
s32 mu // 0.12
|
||||
)
|
||||
{
|
||||
s32 m00 = ((y1 - y0) * i_tension) >> 16; // 16.0
|
||||
s32 m01 = ((y2 - y1) * i_tension) >> 16; // 16.0
|
||||
s32 m0 = m00 + m01;
|
||||
|
||||
s32 m10 = ((y2 - y1) * i_tension) >> 16; // 16.0
|
||||
s32 m11 = ((y3 - y2) * i_tension) >> 16; // 16.0
|
||||
s32 m1 = m10 + m11;
|
||||
|
||||
s32 val = ((2 * y1 + m0 + m1 - 2 * y2) * mu) >> 12; // 16.0
|
||||
val = ((val - 3 * y1 - 2 * m0 - m1 + 3 * y2) * mu) >> 12; // 16.0
|
||||
val = ((val + m0) * mu) >> 12; // 16.0
|
||||
|
||||
return (val + (y1));
|
||||
}
|
||||
|
||||
__forceinline static s32 CatmullRomInterpolate(
|
||||
s32 y0, // 16.0
|
||||
s32 y1, // 16.0
|
||||
s32 y2, // 16.0
|
||||
s32 y3, // 16.0
|
||||
s32 mu // 0.12
|
||||
)
|
||||
{
|
||||
//q(t) = 0.5 *( (2 * P1) +
|
||||
// (-P0 + P2) * t +
|
||||
// (2*P0 - 5*P1 + 4*P2 - P3) * t2 +
|
||||
// (-P0 + 3*P1- 3*P2 + P3) * t3)
|
||||
|
||||
s32 a3 = (-y0 + 3 * y1 - 3 * y2 + y3);
|
||||
s32 a2 = (2 * y0 - 5 * y1 + 4 * y2 - y3);
|
||||
s32 a1 = (-y0 + y2);
|
||||
s32 a0 = (2 * y1);
|
||||
|
||||
s32 val = ((a3)*mu) >> 12;
|
||||
val = ((a2 + val) * mu) >> 12;
|
||||
val = ((a1 + val) * mu) >> 12;
|
||||
|
||||
return (a0 + val) >> 1;
|
||||
}
|
||||
|
||||
__forceinline static s32 CubicInterpolate(
|
||||
s32 y0, // 16.0
|
||||
s32 y1, // 16.0
|
||||
s32 y2, // 16.0
|
||||
s32 y3, // 16.0
|
||||
s32 mu // 0.12
|
||||
)
|
||||
{
|
||||
const s32 a0 = y3 - y2 - y0 + y1;
|
||||
const s32 a1 = y0 - y1 - a0;
|
||||
const s32 a2 = y2 - y0;
|
||||
|
||||
s32 val = ((a0)*mu) >> 12;
|
||||
val = ((val + a1) * mu) >> 12;
|
||||
val = ((val + a2) * mu) >> 12;
|
||||
|
||||
return (val + y1);
|
||||
}
|
||||
|
||||
// Returns a 16 bit result in Value.
|
||||
// Uses standard template-style optimization techniques to statically generate five different
|
||||
// versions of this function (one for each type of interpolation).
|
||||
template <int InterpType>
|
||||
static __forceinline s32 GetVoiceValues(V_Core& thiscore, uint voiceidx)
|
||||
{
|
||||
V_Voice& vc(thiscore.Voices[voiceidx]);
|
||||
|
||||
while (vc.SP >= 0)
|
||||
{
|
||||
if (InterpType >= 2)
|
||||
{
|
||||
vc.PV4 = vc.PV3;
|
||||
vc.PV3 = vc.PV2;
|
||||
}
|
||||
vc.PV2 = vc.PV1;
|
||||
vc.PV1 = GetNextDataBuffered(thiscore, voiceidx);
|
||||
vc.SP -= 0x1000;
|
||||
}
|
||||
|
||||
const s32 mu = vc.SP + 0x1000;
|
||||
|
||||
switch (InterpType)
|
||||
{
|
||||
case 0:
|
||||
return vc.PV1;
|
||||
case 1:
|
||||
return (vc.PV1) - (((vc.PV2 - vc.PV1) * mu) >> 12);
|
||||
|
||||
case 2:
|
||||
return CubicInterpolate(vc.PV4, vc.PV3, vc.PV2, vc.PV1, mu);
|
||||
case 3:
|
||||
return HermiteInterpolate<16384>(vc.PV4, vc.PV3, vc.PV2, vc.PV1, mu);
|
||||
case 4:
|
||||
return CatmullRomInterpolate(vc.PV4, vc.PV3, vc.PV2, vc.PV1, mu);
|
||||
case 5:
|
||||
return GaussianInterpolate(vc.PV4, vc.PV3, vc.PV2, vc.PV1, (mu & 0x0ff0) >> 4);
|
||||
|
||||
jNO_DEFAULT;
|
||||
}
|
||||
|
||||
return 0; // technically unreachable!
|
||||
}
|
||||
|
||||
// This is Dr. Hell's noise algorithm as implemented in pcsxr
|
||||
// Supposedly this is 100% accurate
|
||||
static __forceinline void UpdateNoise(V_Core& thiscore)
|
||||
{
|
||||
static const uint8_t noise_add[64] = {
|
||||
1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1};
|
||||
|
||||
static const uint16_t noise_freq_add[5] = {
|
||||
0, 84, 140, 180, 210};
|
||||
|
||||
|
||||
u32 level = 0x8000 >> (thiscore.NoiseClk >> 2);
|
||||
level <<= 16;
|
||||
|
||||
thiscore.NoiseCnt += 0x10000;
|
||||
|
||||
thiscore.NoiseCnt += noise_freq_add[thiscore.NoiseClk & 3];
|
||||
if ((thiscore.NoiseCnt & 0xffff) >= noise_freq_add[4])
|
||||
{
|
||||
thiscore.NoiseCnt += 0x10000;
|
||||
thiscore.NoiseCnt -= noise_freq_add[thiscore.NoiseClk & 3];
|
||||
}
|
||||
|
||||
if (thiscore.NoiseCnt >= level)
|
||||
{
|
||||
while (thiscore.NoiseCnt >= level)
|
||||
thiscore.NoiseCnt -= level;
|
||||
|
||||
thiscore.NoiseOut = (thiscore.NoiseOut << 1) | noise_add[(thiscore.NoiseOut >> 10) & 63];
|
||||
}
|
||||
}
|
||||
|
||||
static __forceinline s32 GetNoiseValues(V_Core& thiscore)
|
||||
{
|
||||
return (s16)thiscore.NoiseOut;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
|
||||
// writes a signed value to the SPU2 ram
|
||||
// Performs no cache invalidation -- use only for dynamic memory ranges
|
||||
// of the SPU2 (between 0x0000 and SPU2_DYN_MEMLINE)
|
||||
static __forceinline void spu2M_WriteFast(u32 addr, s16 value)
|
||||
{
|
||||
// Fixes some of the oldest hangs in pcsx2's history! :p
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (Cores[i].IRQEnable && Cores[i].IRQA == addr)
|
||||
{
|
||||
//printf("Core %d special write IRQ Called (IRQ passed). IRQA = %x\n",i,addr);
|
||||
SetIrqCall(i);
|
||||
}
|
||||
}
|
||||
// throw an assertion if the memory range is invalid:
|
||||
#ifndef DEBUG_FAST
|
||||
pxAssume(addr < SPU2_DYN_MEMLINE);
|
||||
#endif
|
||||
*GetMemPtr(addr) = value;
|
||||
}
|
||||
|
||||
|
||||
static __forceinline StereoOut32 MixVoice(uint coreidx, uint voiceidx)
|
||||
{
|
||||
V_Core& thiscore(Cores[coreidx]);
|
||||
V_Voice& vc(thiscore.Voices[voiceidx]);
|
||||
|
||||
// If this assertion fails, it mans SCurrent is being corrupted somewhere, or is not initialized
|
||||
// properly. Invalid values in SCurrent will cause errant IRQs and corrupted audio.
|
||||
pxAssertMsg((vc.SCurrent <= 28) && (vc.SCurrent != 0), "Current sample should always range from 1->28");
|
||||
|
||||
// Most games don't use much volume slide effects. So only call the UpdateVolume
|
||||
// methods when needed by checking the flag outside the method here...
|
||||
// (Note: Ys 6 : Ark of Nephistm uses these effects)
|
||||
|
||||
vc.Volume.Update();
|
||||
|
||||
// SPU2 Note: The spu2 continues to process voices for eternity, always, so we
|
||||
// have to run through all the motions of updating the voice regardless of it's
|
||||
// audible status. Otherwise IRQs might not trigger and emulation might fail.
|
||||
|
||||
UpdatePitch(coreidx, voiceidx);
|
||||
|
||||
StereoOut32 voiceOut(0, 0);
|
||||
s32 Value = 0;
|
||||
|
||||
if (vc.ADSR.Phase > 0)
|
||||
{
|
||||
if (vc.Noise)
|
||||
Value = GetNoiseValues(thiscore);
|
||||
else
|
||||
{
|
||||
// Optimization : Forceinline'd Templated Dispatch Table. Any halfwit compiler will
|
||||
// turn this into a clever jump dispatch table (no call/rets, no compares, uber-efficient!)
|
||||
|
||||
switch (Interpolation)
|
||||
{
|
||||
case 0:
|
||||
Value = GetVoiceValues<0>(thiscore, voiceidx);
|
||||
break;
|
||||
case 1:
|
||||
Value = GetVoiceValues<1>(thiscore, voiceidx);
|
||||
break;
|
||||
case 2:
|
||||
Value = GetVoiceValues<2>(thiscore, voiceidx);
|
||||
break;
|
||||
case 3:
|
||||
Value = GetVoiceValues<3>(thiscore, voiceidx);
|
||||
break;
|
||||
case 4:
|
||||
Value = GetVoiceValues<4>(thiscore, voiceidx);
|
||||
break;
|
||||
case 5:
|
||||
Value = GetVoiceValues<5>(thiscore, voiceidx);
|
||||
break;
|
||||
|
||||
jNO_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
// Update and Apply ADSR (applies to normal and noise sources)
|
||||
//
|
||||
// Note! It's very important that ADSR stay as accurate as possible. By the way
|
||||
// it is used, various sound effects can end prematurely if we truncate more than
|
||||
// one or two bits. Best result comes from no truncation at all, which is why we
|
||||
// use a full 64-bit multiply/result here.
|
||||
|
||||
CalculateADSR(thiscore, voiceidx);
|
||||
Value = ApplyVolume(Value, vc.ADSR.Value);
|
||||
vc.OutX = Value;
|
||||
|
||||
if (IsDevBuild)
|
||||
DebugCores[coreidx].Voices[voiceidx].displayPeak = std::max(DebugCores[coreidx].Voices[voiceidx].displayPeak, (s32)vc.OutX);
|
||||
|
||||
voiceOut = ApplyVolume(StereoOut32(Value, Value), vc.Volume);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (vc.SP >= 0)
|
||||
GetNextDataDummy(thiscore, voiceidx); // Dummy is enough
|
||||
}
|
||||
|
||||
// Write-back of raw voice data (post ADSR applied)
|
||||
if (voiceidx == 1)
|
||||
spu2M_WriteFast(((0 == coreidx) ? 0x400 : 0xc00) + OutPos, Value);
|
||||
else if (voiceidx == 3)
|
||||
spu2M_WriteFast(((0 == coreidx) ? 0x600 : 0xe00) + OutPos, Value);
|
||||
|
||||
return voiceOut;
|
||||
}
|
||||
|
||||
const VoiceMixSet VoiceMixSet::Empty((StereoOut32()), (StereoOut32())); // Don't use SteroOut32::Empty because C++ doesn't make any dep/order checks on global initializers.
|
||||
|
||||
static __forceinline void MixCoreVoices(VoiceMixSet& dest, const uint coreidx)
|
||||
{
|
||||
V_Core& thiscore(Cores[coreidx]);
|
||||
|
||||
for (uint voiceidx = 0; voiceidx < V_Core::NumVoices; ++voiceidx)
|
||||
{
|
||||
StereoOut32 VVal(MixVoice(coreidx, voiceidx));
|
||||
|
||||
// Note: Results from MixVoice are ranged at 16 bits.
|
||||
|
||||
dest.Dry.Left += VVal.Left & thiscore.VoiceGates[voiceidx].DryL;
|
||||
dest.Dry.Right += VVal.Right & thiscore.VoiceGates[voiceidx].DryR;
|
||||
dest.Wet.Left += VVal.Left & thiscore.VoiceGates[voiceidx].WetL;
|
||||
dest.Wet.Right += VVal.Right & thiscore.VoiceGates[voiceidx].WetR;
|
||||
}
|
||||
}
|
||||
|
||||
StereoOut32 V_Core::Mix(const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext)
|
||||
{
|
||||
MasterVol.Update();
|
||||
UpdateNoise(*this);
|
||||
|
||||
|
||||
// Saturate final result to standard 16 bit range.
|
||||
const VoiceMixSet Voices(clamp_mix(inVoices.Dry), clamp_mix(inVoices.Wet));
|
||||
|
||||
// Write Mixed results To Output Area
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1000 : 0x1800) + OutPos, Voices.Dry.Left);
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1200 : 0x1A00) + OutPos, Voices.Dry.Right);
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1400 : 0x1C00) + OutPos, Voices.Wet.Left);
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1600 : 0x1E00) + OutPos, Voices.Wet.Right);
|
||||
|
||||
// Write mixed results to logfile (if enabled)
|
||||
|
||||
WaveDump::WriteCore(Index, CoreSrc_DryVoiceMix, Voices.Dry);
|
||||
WaveDump::WriteCore(Index, CoreSrc_WetVoiceMix, Voices.Wet);
|
||||
|
||||
// Mix in the Input data
|
||||
|
||||
StereoOut32 TD(
|
||||
Input.Left & DryGate.InpL,
|
||||
Input.Right & DryGate.InpR);
|
||||
|
||||
// Mix in the Voice data
|
||||
TD.Left += Voices.Dry.Left & DryGate.SndL;
|
||||
TD.Right += Voices.Dry.Right & DryGate.SndR;
|
||||
|
||||
// Mix in the External (nothing/core0) data
|
||||
TD.Left += Ext.Left & DryGate.ExtL;
|
||||
TD.Right += Ext.Right & DryGate.ExtR;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Reverberation Effects Processing
|
||||
// ----------------------------------------------------------------------------
|
||||
// SPU2 has an FxEnable bit which seems to disable all reverb processing *and*
|
||||
// output, but does *not* disable the advancing buffers. IRQs are not triggered
|
||||
// and reverb is rendered silent.
|
||||
//
|
||||
// Technically we should advance the buffers even when fx are disabled. However
|
||||
// there are two things that make this very unlikely to matter:
|
||||
//
|
||||
// 1. Any SPU2 app wanting to avoid noise or pops needs to clear the reverb buffers
|
||||
// when adjusting settings anyway; so the read/write positions in the reverb
|
||||
// buffer after FxEnabled is set back to 1 doesn't really matter.
|
||||
//
|
||||
// 2. Writes to ESA (and possibly EEA) reset the buffer pointers to 0.
|
||||
//
|
||||
// On the other hand, updating the buffer is cheap and easy, so might as well. ;)
|
||||
|
||||
Reverb_AdvanceBuffer(); // Updates the reverb work area as well, if needed.
|
||||
|
||||
// ToDo:
|
||||
// Bad EndA causes memory corruption. Bad for us, unknown on PS2!
|
||||
// According to no$psx, effects always run but don't always write back, so the FxEnable check may be wrong
|
||||
if (!FxEnable || EffectsEndA >= 0x100000)
|
||||
return TD;
|
||||
|
||||
StereoOut32 TW;
|
||||
|
||||
// Mix Input, Voice, and External data:
|
||||
|
||||
TW.Left = Input.Left & WetGate.InpL;
|
||||
TW.Right = Input.Right & WetGate.InpR;
|
||||
|
||||
TW.Left += Voices.Wet.Left & WetGate.SndL;
|
||||
TW.Right += Voices.Wet.Right & WetGate.SndR;
|
||||
TW.Left += Ext.Left & WetGate.ExtL;
|
||||
TW.Right += Ext.Right & WetGate.ExtR;
|
||||
|
||||
WaveDump::WriteCore(Index, CoreSrc_PreReverb, TW);
|
||||
|
||||
StereoOut32 RV = DoReverb(TW);
|
||||
|
||||
WaveDump::WriteCore(Index, CoreSrc_PostReverb, RV);
|
||||
|
||||
// Mix Dry + Wet
|
||||
// (master volume is applied later to the result of both outputs added together).
|
||||
return TD + ApplyVolume(RV, FxVol);
|
||||
}
|
||||
|
||||
// used to throttle the output rate of cache stat reports
|
||||
static int p_cachestat_counter = 0;
|
||||
|
||||
// Gcc does not want to inline it when lto is enabled because some functions growth too much.
|
||||
// The function is big enought to see any speed impact. -- Gregory
|
||||
#ifndef __POSIX__
|
||||
__forceinline
|
||||
#endif
|
||||
void
|
||||
Mix()
|
||||
{
|
||||
// Note: Playmode 4 is SPDIF, which overrides other inputs.
|
||||
StereoOut32 InputData[2] =
|
||||
{
|
||||
// SPDIF is on Core 0:
|
||||
// Fixme:
|
||||
// 1. We do not have an AC3 decoder for the bitstream.
|
||||
// 2. Games usually provide a normal ADMA stream as well and want to see it getting read!
|
||||
/*(PlayMode&4) ? StereoOut32::Empty : */ ApplyVolume(Cores[0].ReadInput(), Cores[0].InpVol),
|
||||
|
||||
// CDDA is on Core 1:
|
||||
(PlayMode & 8) ? StereoOut32::Empty : ApplyVolume(Cores[1].ReadInput(), Cores[1].InpVol)};
|
||||
|
||||
WaveDump::WriteCore(0, CoreSrc_Input, InputData[0]);
|
||||
WaveDump::WriteCore(1, CoreSrc_Input, InputData[1]);
|
||||
|
||||
// Todo: Replace me with memzero initializer!
|
||||
VoiceMixSet VoiceData[2] = {VoiceMixSet::Empty, VoiceMixSet::Empty}; // mixed voice data for each core.
|
||||
MixCoreVoices(VoiceData[0], 0);
|
||||
MixCoreVoices(VoiceData[1], 1);
|
||||
|
||||
StereoOut32 Ext(Cores[0].Mix(VoiceData[0], InputData[0], StereoOut32::Empty));
|
||||
|
||||
if ((PlayMode & 4) || (Cores[0].Mute != 0))
|
||||
Ext = StereoOut32::Empty;
|
||||
else
|
||||
{
|
||||
Ext = clamp_mix(ApplyVolume(Ext, Cores[0].MasterVol));
|
||||
}
|
||||
|
||||
// Commit Core 0 output to ram before mixing Core 1:
|
||||
spu2M_WriteFast(0x800 + OutPos, Ext.Left);
|
||||
spu2M_WriteFast(0xA00 + OutPos, Ext.Right);
|
||||
|
||||
WaveDump::WriteCore(0, CoreSrc_External, Ext);
|
||||
|
||||
Ext = ApplyVolume(Ext, Cores[1].ExtVol);
|
||||
StereoOut32 Out(Cores[1].Mix(VoiceData[1], InputData[1], Ext));
|
||||
|
||||
if (PlayMode & 8)
|
||||
{
|
||||
// Experimental CDDA support
|
||||
// The CDDA overrides all other mixer output. It's a direct feed!
|
||||
|
||||
Out = Cores[1].ReadInput_HiFi();
|
||||
//WaveLog::WriteCore( 1, "CDDA-32", OutL, OutR );
|
||||
}
|
||||
else
|
||||
{
|
||||
Out.Left = MulShr32(Out.Left << SndOutVolumeShift, Cores[1].MasterVol.Left.Value);
|
||||
Out.Right = MulShr32(Out.Right << SndOutVolumeShift, Cores[1].MasterVol.Right.Value);
|
||||
|
||||
// Final Clamp!
|
||||
// Like any good audio system, the PS2 pumps the volume and incurs some distortion in its
|
||||
// output, giving us a nice thumpy sound at times. So we add 1 above (2x volume pump) and
|
||||
// then clamp it all here.
|
||||
|
||||
// Edit: I'm sorry Jake, but I know of no good audio system that arbitrary distorts and clips
|
||||
// output by design.
|
||||
// Good thing though that this code gets the volume exactly right, as per tests :)
|
||||
Out = clamp_mix(Out, SndOutVolumeShift);
|
||||
}
|
||||
|
||||
// Configurable output volume
|
||||
Out.Left *= FinalVolume;
|
||||
Out.Right *= FinalVolume;
|
||||
|
||||
//SndBuffer::Write(Out);
|
||||
|
||||
//Host::WriteToSoundBuffer(Out.Left >> 12,Out.Right >> 12);
|
||||
Host::WriteToSoundBuffer(Out.DownSample().Left,Out.DownSample().Right);
|
||||
if (SampleRate == 96000) // Double up samples for 96khz (Port Audio Non-Exclusive)
|
||||
Host::WriteToSoundBuffer(Out.DownSample().Left,Out.DownSample().Right);
|
||||
|
||||
// Update AutoDMA output positioning
|
||||
OutPos++;
|
||||
if (OutPos >= 0x200)
|
||||
OutPos = 0;
|
||||
|
||||
if (IsDevBuild)
|
||||
{
|
||||
p_cachestat_counter++;
|
||||
if (p_cachestat_counter > (48000 * 10))
|
||||
{
|
||||
p_cachestat_counter = 0;
|
||||
if (MsgCache())
|
||||
ConLog(" * SPU2 > CacheStats > Hits: %d Misses: %d Ignores: %d\n",
|
||||
g_counter_cache_hits,
|
||||
g_counter_cache_misses,
|
||||
g_counter_cache_ignores);
|
||||
|
||||
g_counter_cache_hits =
|
||||
g_counter_cache_misses =
|
||||
g_counter_cache_ignores = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "SPU2/Global.h"
|
||||
|
||||
namespace Host
|
||||
{
|
||||
void WriteToSoundBuffer(s16 Left, s16 Right);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2022, OpenEmu Team
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the OpenEmu Team nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef keymap_h
|
||||
#define keymap_h
|
||||
|
||||
#include "PAD/Host/Global.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gamePadValues ps2key;
|
||||
}keymap;
|
||||
|
||||
keymap ps2keymap[25]={
|
||||
{PAD_UP}, // OEPS2ButtonUp,
|
||||
{PAD_DOWN}, // OEPS2ButtonDown,
|
||||
{PAD_LEFT}, // OEPS2ButtonLeft,
|
||||
{PAD_RIGHT}, // OEPS2ButtonRight,
|
||||
{PAD_TRIANGLE}, // OEPS2ButtonTriangle,
|
||||
{PAD_CIRCLE}, // OEPS2ButtonCircle,
|
||||
{PAD_CROSS}, // OEPS2ButtonCross,
|
||||
{PAD_SQUARE}, // OEPS2ButtonSquare,
|
||||
{PAD_L1}, // OEPS2ButtonL1,
|
||||
{PAD_L2}, // OEPS2ButtonL2,
|
||||
{PAD_L3}, // OEPS2ButtonL3,
|
||||
{PAD_R1}, // OEPS2ButtonR1,
|
||||
{PAD_R2}, // OEPS2ButtonR2,
|
||||
{PAD_R3}, // OEPS2ButtonR3,
|
||||
{PAD_START}, // OEPS2ButtonStart,
|
||||
{PAD_SELECT}, // OEPS2ButtonSelect,
|
||||
{}, // OEPS2ButtonAnalogMode,
|
||||
{PAD_L_UP}, // OEPS2LeftAnalogUp,
|
||||
{PAD_L_DOWN}, // OEPS2LeftAnalogDown,
|
||||
{PAD_L_LEFT}, // OEPS2LeftAnalogLeft,
|
||||
{PAD_L_RIGHT}, // OEPS2LeftAnalogRight,
|
||||
{PAD_R_UP}, // OEPS2RightAnalogUp,
|
||||
{PAD_R_DOWN}, // OEPS2RightAnalogDown,
|
||||
{PAD_R_LEFT}, // OEPS2RightAnalogLeft,
|
||||
{PAD_R_RIGHT}, // OEPS2RightAnalogRight
|
||||
};
|
||||
#endif /* keymap_h */
|
||||
@@ -0,0 +1,7 @@
|
||||
# PCSX2Exports.exp
|
||||
# PCSX2
|
||||
#
|
||||
# Created by C.W. Betts on 2/2/22.
|
||||
#
|
||||
|
||||
.objc_class_name_PCSX2GameCore
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2021, OpenEmu Team
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the OpenEmu Team nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <OpenEmuBase/OEGameCore.h>
|
||||
#import "OEPS2SystemResponderClient.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface PCSX2GameCore : OEGameCore <OEPS2SystemResponderClient>
|
||||
|
||||
@end
|
||||
|
||||
extern PCSX2GameCore *_current;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,676 @@
|
||||
// Copyright (c) 2021, OpenEmu Team
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the OpenEmu Team nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import "PCSX2GameCore.h"
|
||||
#import <OpenEmuBase/OETimingUtils.h>
|
||||
#import <OpenEmuBase/OERingBuffer.h>
|
||||
#include "Audio/OESndOut.h"
|
||||
#include "Input/keymap.h"
|
||||
|
||||
#define BOOL PCSX2BOOL
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GS.h"
|
||||
#include "HostSettings.h"
|
||||
#include "HostDisplay.h"
|
||||
#include "VMManager.h"
|
||||
#include "AppConfig.h"
|
||||
#include "Frontend/InputManager.h"
|
||||
#include "Frontend/INISettingsInterface.h"
|
||||
#include "Frontend/OpenGLHostDisplay.h"
|
||||
#include "common/SettingsWrapper.h"
|
||||
#include "CDVD/CDVDaccess.h"
|
||||
#include "SPU2/Global.h"
|
||||
#include "SPU2/SndOut.h"
|
||||
#include "PAD/Host/KeyStatus.h"
|
||||
#include "R3000A.h"
|
||||
#include "MTVU.h"
|
||||
#undef BOOL
|
||||
|
||||
#include <OpenGL/gl3.h>
|
||||
#include <OpenGL/gl3ext.h>
|
||||
|
||||
std::unique_ptr<AppConfig> g_Conf;
|
||||
static bool ExitRequested = false;
|
||||
|
||||
bool renderswitch = false;
|
||||
|
||||
namespace GSDump
|
||||
{
|
||||
bool isRunning = false;
|
||||
}
|
||||
|
||||
alignas(16) static SysMtgsThread s_mtgs_thread;
|
||||
PCSX2GameCore *_current;
|
||||
|
||||
@interface PCSX2GameCore ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation PCSX2GameCore {
|
||||
@package
|
||||
bool hasInitialized;
|
||||
NSString* gamePath;
|
||||
std::unique_ptr<INISettingsInterface> s_base_settings_interface;
|
||||
std::unique_ptr<HostDisplay> hostDisplay;
|
||||
|
||||
VMBootParameters params;
|
||||
|
||||
//Multi-disc booting.
|
||||
NSUInteger _maxDiscs;
|
||||
NSMutableArray<NSString*> *_allCueSheetFiles;
|
||||
NSString *basePath;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_current = self;
|
||||
VMManager::InitializeMemory();
|
||||
_maxDiscs = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static NSString *binCueFix(NSString *path)
|
||||
{
|
||||
if ([[path pathExtension] caseInsensitiveCompare:@"cue"] == NSOrderedSame) {
|
||||
// Assume the bin file is the same as the cue.
|
||||
return [[path stringByDeletingPathExtension] stringByAppendingPathExtension:@"bin"];
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
- (BOOL)loadFileAtPath:(NSString *)path error:(NSError **)error
|
||||
{
|
||||
// PCSX2 can't handle cue files... but can read bin files
|
||||
if ([[path pathExtension] caseInsensitiveCompare:@"cue"] == NSOrderedSame) {
|
||||
// Assume the bin file is the same name as the cue.
|
||||
gamePath = [[path stringByDeletingPathExtension] stringByAppendingPathExtension:@"bin"];
|
||||
} else if([path.pathExtension.lowercaseString isEqualToString:@"m3u"]) {
|
||||
basePath = path.stringByDeletingLastPathComponent;
|
||||
NSString *m3uString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@".*\\.cue|.*\\.ccd|.*\\.iso" options:NSRegularExpressionCaseInsensitive error:nil];
|
||||
NSUInteger numberOfMatches = [regex numberOfMatchesInString:m3uString options:0 range:NSMakeRange(0, m3uString.length)];
|
||||
|
||||
NSLog(@"[PCSX2] Loaded m3u containing %lu cue sheets or ccd", numberOfMatches);
|
||||
|
||||
_maxDiscs = numberOfMatches;
|
||||
|
||||
// Keep track of cue sheets for use with SBI files
|
||||
[regex enumerateMatchesInString:m3uString options:0 range:NSMakeRange(0, m3uString.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
||||
NSRange range = result.range;
|
||||
NSString *match = [m3uString substringWithRange:range];
|
||||
|
||||
if([match containsString:@".cue"] || [match containsString:@".iso"]) {
|
||||
[_allCueSheetFiles addObject:[m3uString substringWithRange:range]];
|
||||
}
|
||||
}];
|
||||
|
||||
if (_allCueSheetFiles.count <= 0) {
|
||||
if (error) {
|
||||
*error = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotLoadROMError userInfo:@{NSFilePathErrorKey: path}];
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
NSString *ToPassBack = [[basePath stringByAppendingPathComponent:_allCueSheetFiles.firstObject] stringByStandardizingPath];
|
||||
ToPassBack = binCueFix(ToPassBack);
|
||||
|
||||
gamePath = ToPassBack;
|
||||
}
|
||||
} else {
|
||||
gamePath = [path copy];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)loadStateFromFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block
|
||||
{
|
||||
// FIXME: fix save states.
|
||||
bool success = true; //VMManager::LoadState(fileName.fileSystemRepresentation);
|
||||
//block(success, success ? nil : [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotLoadStateError userInfo:@{NSFilePathErrorKey: fileName}]);
|
||||
block(success, nil);
|
||||
}
|
||||
|
||||
- (void)saveStateToFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block
|
||||
{
|
||||
// FIXME: fix save states.
|
||||
Console.Error("SaveState Requested");
|
||||
bool success = true ; //VMManager::SaveState(fileName.fileSystemRepresentation);
|
||||
//block(success, success ? nil : [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotSaveStateError userInfo:@{NSFilePathErrorKey: fileName}]);
|
||||
block(success, nil);
|
||||
}
|
||||
|
||||
- (void)setupEmulation
|
||||
{
|
||||
const std::string pcsx2ini(Path::CombineStdString([self.supportDirectoryPath stringByAppendingPathComponent:@"/inis"].fileSystemRepresentation, "PCSX2.ini"));
|
||||
s_base_settings_interface = std::make_unique<INISettingsInterface>(std::move(pcsx2ini));
|
||||
Host::Internal::SetBaseSettingsLayer(s_base_settings_interface.get());
|
||||
|
||||
//EmuConfig = Pcsx2Config();
|
||||
EmuFolders::SetDefaults();
|
||||
|
||||
SettingsInterface& si = *s_base_settings_interface.get();
|
||||
si.SetUIntValue("UI", "SettingsVersion", 1);
|
||||
|
||||
{
|
||||
SettingsSaveWrapper wrapper(si);
|
||||
EmuConfig.LoadSave(wrapper);
|
||||
}
|
||||
|
||||
NSString *path = self.batterySavesDirectoryPath;
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:NULL]) {
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:NULL];
|
||||
}
|
||||
|
||||
EmuFolders::MemoryCards = path.fileSystemRepresentation;
|
||||
EmuFolders::Bios = self.biosDirectoryPath.fileSystemRepresentation;
|
||||
EmuFolders::AppRoot = [[NSBundle bundleForClass:[self class]] resourceURL].fileSystemRepresentation;
|
||||
EmuFolders::DataRoot = self.supportDirectoryPath.fileSystemRepresentation;
|
||||
EmuFolders::Settings = [self.supportDirectoryPath stringByAppendingPathComponent:@"/inis"].fileSystemRepresentation;
|
||||
EmuFolders::Resources = [[NSBundle bundleForClass:[self class]] resourceURL].fileSystemRepresentation;
|
||||
EmuFolders::Cache = [self.supportDirectoryPath stringByAppendingPathComponent:@"/Cache"].fileSystemRepresentation;
|
||||
EmuFolders::Snapshots = [self.supportDirectoryPath stringByAppendingPathComponent:@"/snaps"].fileSystemRepresentation;
|
||||
EmuFolders::Savestates = [self.supportDirectoryPath stringByAppendingPathComponent:@"/sstates"].fileSystemRepresentation;
|
||||
EmuFolders::Logs = [self.supportDirectoryPath stringByAppendingPathComponent:@"/Logs"].fileSystemRepresentation;
|
||||
EmuFolders::Cheats = [self.supportDirectoryPath stringByAppendingPathComponent:@"/Cheats"].fileSystemRepresentation;
|
||||
EmuFolders::CheatsWS = [self.supportDirectoryPath stringByAppendingPathComponent:@"/cheats_ws"].fileSystemRepresentation;
|
||||
EmuFolders::Covers = [self.supportDirectoryPath stringByAppendingPathComponent:@"/Covers"].fileSystemRepresentation;
|
||||
EmuFolders::GameSettings = [self.supportDirectoryPath stringByAppendingPathComponent:@"/gamesettings"].fileSystemRepresentation;
|
||||
EmuFolders::EnsureFoldersExist();
|
||||
|
||||
EmuConfig.Mcd[0].Enabled = true;
|
||||
EmuConfig.Mcd[0].Type = MemoryCardType::Folder;
|
||||
EmuConfig.Mcd[0].Filename = "Memory folder 1.ps2";
|
||||
|
||||
EmuConfig.Mcd[1].Enabled = true;
|
||||
EmuConfig.Mcd[1].Type = MemoryCardType::Folder;
|
||||
EmuConfig.Mcd[1].Filename = "Memory folder 2.ps2";
|
||||
|
||||
// TODO: select based on loaded game's region?
|
||||
EmuConfig.BaseFilenames.Bios = "scph39001.bin";
|
||||
|
||||
#ifdef DEBUG
|
||||
si.SetBoolValue("EmuCore/CPU/Recompiler", "EnableEE", false);
|
||||
#else
|
||||
si.SetBoolValue("EmuCore/CPU/Recompiler", "EnableEE", true);
|
||||
#endif
|
||||
si.SetBoolValue("EmuCore/CPU/Recompiler", "EnableEECache", false);
|
||||
si.SetBoolValue("EmuCore/CPU/Recompiler", "EnableIOP", true);
|
||||
si.SetBoolValue("EmuCore/CPU/Recompiler", "EnableVU0", true);
|
||||
si.SetBoolValue("EmuCore/CPU/Recompiler", "EnableVU1", true);
|
||||
si.SetStringValue("EmuCore/SPU2", "OutputModule", "NullOut");
|
||||
si.SetBoolValue("", "EnableGameFixes", true);
|
||||
si.SetBoolValue("EmuCore", "EnablePatches", true);
|
||||
si.SetBoolValue("EmuCore", "EnableCheats", false);
|
||||
si.SetBoolValue("EmuCore", "EnablePerGameSettings", true);
|
||||
si.SetBoolValue("EmuCore", "HostFs", false);
|
||||
si.SetBoolValue("EmuCore/Speedhacks", "vuFlagHack", true);
|
||||
si.SetBoolValue("EmuCore/Speedhacks", "IntcStat", true);
|
||||
si.SetBoolValue("EmuCore/Speedhacks", "WaitLoop", true);
|
||||
si.SetIntValue("EmuCore/GS", "FramesToDraw", 1);
|
||||
si.SetIntValue("EmuCore/GS", "upscale_multiplier", 2);
|
||||
si.SetBoolValue("EmuCore/GS", "FrameLimitEnable", true);
|
||||
si.SetBoolValue("EmuCore/GS", "SyncToHostRefreshRate",false);
|
||||
si.SetBoolValue("EmuCore/GS", "UserHacks", true);
|
||||
si.SetBoolValue("EmuCore/GS", "UserHacks_WildHack", true);
|
||||
|
||||
wxModule::RegisterModules();
|
||||
wxModule::InitializeModules();
|
||||
}
|
||||
|
||||
- (void)resetEmulation
|
||||
{
|
||||
VMManager::SetState(VMState::Stopping);
|
||||
}
|
||||
|
||||
- (void)setPauseEmulation:(BOOL)pauseEmulation
|
||||
{
|
||||
if (pauseEmulation) {
|
||||
VMManager::SetState(VMState::Paused);
|
||||
} else {
|
||||
VMManager::SetState(VMState::Running);
|
||||
}
|
||||
[super setPauseEmulation:pauseEmulation];
|
||||
}
|
||||
|
||||
- (void)startEmulation
|
||||
{
|
||||
[super startEmulation];
|
||||
|
||||
[self.renderDelegate willRenderFrameOnAlternateThread];
|
||||
[self.renderDelegate suspendFPSLimiting];
|
||||
|
||||
params.source = gamePath.fileSystemRepresentation;
|
||||
params.save_state = "";
|
||||
params.source_type = CDVD_SourceType::Iso;
|
||||
params.elf_override = "";
|
||||
params.fast_boot = true;
|
||||
params.fullscreen = false;
|
||||
params.batch_mode = std::nullopt;
|
||||
|
||||
if(!hasInitialized){
|
||||
hostDisplay = HostDisplay::CreateDisplayForAPI(OpenGLHostDisplay::RenderAPI::OpenGL);
|
||||
WindowInfo wi;
|
||||
wi.type = WindowInfo::Type::MacOS;
|
||||
wi.surface_width = 640 ;
|
||||
wi.surface_height = 448 ;
|
||||
hostDisplay->CreateRenderDevice(wi,
|
||||
Host::GetStringSettingValue("EmuCore/GS", "Adapter", ""),
|
||||
VsyncMode::Adaptive,
|
||||
Host::GetBoolSettingValue("EmuCore/GS", "ThreadedPresentation", false),
|
||||
Host::GetBoolSettingValue("EmuCore/GS", "UseDebugDevice", false));
|
||||
|
||||
|
||||
if(VMManager::Initialize(params)){
|
||||
hasInitialized = true;
|
||||
VMManager::SetState(VMState::Running);
|
||||
[NSThread detachNewThreadSelector:@selector(runVMThread) toTarget:self withObject:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)runVMThread
|
||||
{
|
||||
OESetThreadRealtime(1. / 50, .007, .03); // guessed from bsnes
|
||||
|
||||
while(!ExitRequested)
|
||||
{
|
||||
if(VMManager::HasValidVM()){
|
||||
VMManager::Execute();
|
||||
}else{
|
||||
if(VMManager::GetState() == VMState::Stopping)
|
||||
VMManager::Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopEmulation
|
||||
{
|
||||
ExitRequested = true;
|
||||
VMManager::SetState(VMState::Stopping);
|
||||
VMManager::Shutdown();
|
||||
[super stopEmulation];
|
||||
}
|
||||
|
||||
- (void)executeFrame
|
||||
{
|
||||
//Console.Error("UpScale Multiplier: %d", GSConfig.UpscaleMultiplier);
|
||||
// if(VMManager::HasValidVM()){
|
||||
// VMManager::Execute();
|
||||
// }
|
||||
}
|
||||
|
||||
#pragma mark Video
|
||||
- (OEIntSize)aspectSize
|
||||
{
|
||||
return (OEIntSize){ 4, 3 };
|
||||
}
|
||||
|
||||
- (NSTimeInterval)frameInterval
|
||||
{
|
||||
return 60;
|
||||
}
|
||||
|
||||
- (BOOL)tryToResizeVideoTo:(OEIntSize)size
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (OEGameCoreRendering)gameCoreRendering
|
||||
{
|
||||
//FIXME: return OEGameCoreRenderingMetal1Video;
|
||||
return OEGameCoreRenderingOpenGL3Video;
|
||||
}
|
||||
|
||||
- (BOOL)hasAlternateRenderingThread
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)needsDoubleBufferedFBO
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (OEIntSize)bufferSize
|
||||
{
|
||||
return (OEIntSize){ 640 , 448 };
|
||||
}
|
||||
|
||||
#pragma mark Audio
|
||||
- (NSUInteger)channelCount
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
- (NSUInteger)audioBitDepth
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
- (double)audioSampleRate
|
||||
{
|
||||
return 48000;
|
||||
}
|
||||
|
||||
#pragma mark Input
|
||||
- (oneway void)didMovePS2JoystickDirection:(OEPS2Button)button withValue:(CGFloat)value forPlayer:(NSUInteger)player
|
||||
{
|
||||
g_key_status.Set(u32(player - 1), ps2keymap[button].ps2key , value);
|
||||
}
|
||||
|
||||
- (oneway void)didPushPS2Button:(OEPS2Button)button forPlayer:(NSUInteger)player
|
||||
{
|
||||
g_key_status.Set(u32(player - 1), ps2keymap[button].ps2key , 1.0f);
|
||||
|
||||
}
|
||||
|
||||
- (oneway void)didReleasePS2Button:(OEPS2Button)button forPlayer:(NSUInteger)player {
|
||||
g_key_status.Set(u32(player - 1), ps2keymap[button].ps2key, 0.0f);
|
||||
}
|
||||
|
||||
#pragma mark - Discs
|
||||
|
||||
- (NSUInteger)discCount
|
||||
{
|
||||
return _maxDiscs ? _maxDiscs : 1;
|
||||
}
|
||||
|
||||
- (void)setDisc:(NSUInteger)discNumber
|
||||
{
|
||||
NSString *ToPassBack = [basePath stringByAppendingPathComponent:_allCueSheetFiles[discNumber - 1]];
|
||||
ToPassBack = [binCueFix(ToPassBack) stringByStandardizingPath];
|
||||
|
||||
gamePath = ToPassBack;
|
||||
|
||||
VMManager::ChangeDisc(gamePath.fileSystemRepresentation);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
SysMtgsThread& GetMTGS()
|
||||
{
|
||||
return s_mtgs_thread;
|
||||
}
|
||||
|
||||
#pragma mark - Host Namespace
|
||||
|
||||
std::optional<std::vector<u8>> Host::ReadResourceFile(const char* filename)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSString *nsFile = @(filename);
|
||||
NSString *baseName = nsFile.lastPathComponent.stringByDeletingPathExtension;
|
||||
NSString *upperName = nsFile.stringByDeletingLastPathComponent;
|
||||
NSString *baseExt = nsFile.pathExtension;
|
||||
if (baseExt.length == 0) {
|
||||
baseExt = nil;
|
||||
}
|
||||
if (upperName.length == 0 || [upperName isEqualToString:@"/"]) {
|
||||
upperName = nil;
|
||||
}
|
||||
NSURL *aURL;
|
||||
if (upperName) {
|
||||
aURL = [[NSBundle bundleForClass:[PCSX2GameCore class]] URLForResource:baseName withExtension:baseExt subdirectory:upperName];
|
||||
} else {
|
||||
aURL = [[NSBundle bundleForClass:[PCSX2GameCore class]] URLForResource:baseName withExtension:baseExt];
|
||||
}
|
||||
if (!aURL) {
|
||||
return std::nullopt;
|
||||
}
|
||||
NSData *data = [[NSData alloc] initWithContentsOfURL:aURL];
|
||||
if (!data) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto retVal = std::vector<u8>(data.length);
|
||||
[data getBytes:retVal.data() length:retVal.size()];
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> Host::ReadResourceFileToString(const char* filename)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSString *nsFile = @(filename);
|
||||
NSString *baseName = nsFile.lastPathComponent.stringByDeletingPathExtension;
|
||||
NSString *upperName = nsFile.stringByDeletingLastPathComponent;
|
||||
NSString *baseExt = nsFile.pathExtension;
|
||||
if (baseExt.length == 0) {
|
||||
baseExt = nil;
|
||||
}
|
||||
if (upperName.length == 0 || [upperName isEqualToString:@"/"]) {
|
||||
upperName = nil;
|
||||
}
|
||||
NSURL *aURL;
|
||||
if (upperName) {
|
||||
aURL = [[NSBundle bundleForClass:[PCSX2GameCore class]] URLForResource:baseName withExtension:baseExt subdirectory:upperName];
|
||||
} else {
|
||||
aURL = [[NSBundle bundleForClass:[PCSX2GameCore class]] URLForResource:baseName withExtension:baseExt];
|
||||
}
|
||||
if (!aURL) {
|
||||
return std::nullopt;
|
||||
}
|
||||
NSData *data = [[NSData alloc] initWithContentsOfURL:aURL];
|
||||
if (!data) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::string ret;
|
||||
ret.resize(data.length);
|
||||
[data getBytes:ret.data() length:ret.size()];
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void Host::WriteToSoundBuffer(s16 Left, s16 Right)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
[[current audioBufferAtIndex:0] write:(&Left) maxLength:sizeof(s16)];
|
||||
[[current audioBufferAtIndex:0] write:(&Right) maxLength:sizeof(s16)];
|
||||
}
|
||||
|
||||
void Host::AddOSDMessage(std::string message, float duration)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Host::AddKeyedOSDMessage(std::string key, std::string message, float duration)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Host::AddFormattedOSDMessage(float duration, const char* format, ...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Host::AddKeyedFormattedOSDMessage(std::string key, float duration, const char* format, ...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Host::RemoveKeyedOSDMessage(std::string key)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Host::ClearOSDMessages()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Host::ReportErrorAsync(const std::string_view& title, const std::string_view& message)
|
||||
{
|
||||
//Console.Error("Reported Error: '%s':'%s'", title, message);
|
||||
}
|
||||
|
||||
#pragma mark Host Thread
|
||||
|
||||
void Host::OnVMStarting()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
void Host::OnVMStarted()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
void Host::OnVMDestroyed()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
void Host::OnVMPaused()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
void Host::OnVMResumed()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
void Host::OnSaveStateLoading(const std::string_view& filename)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
void Host::OnSaveStateLoaded(const std::string_view& filename, bool was_successful)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
void Host::OnSaveStateSaved(const std::string_view& filename)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
void Host::OnGameChanged(const std::string& disc_path, const std::string& game_serial, const std::string& game_name, u32 game_crc)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
void Host::PumpMessagesOnCPUThread()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
}
|
||||
|
||||
void Host::InvalidateSaveStateCache()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Host::RequestResizeHostDisplay(s32 width, s32 height)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
void Host::RunOnCPUThread(std::function<void()> function, bool block)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#pragma mark Host Display
|
||||
|
||||
HostDisplay* Host::AcquireHostDisplay(HostDisplay::RenderAPI api)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN(nullptr);
|
||||
|
||||
return current->hostDisplay.get();
|
||||
}
|
||||
|
||||
void Host::ReleaseHostDisplay()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
HostDisplay* Host::GetHostDisplay()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN(nullptr);
|
||||
|
||||
[current.renderDelegate willRenderFrameOnAlternateThread];
|
||||
return current->hostDisplay.get();
|
||||
}
|
||||
|
||||
bool Host::BeginPresentFrame(bool frame_skip)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN(false);
|
||||
|
||||
return current->hostDisplay.get()->BeginPresent(frame_skip);
|
||||
}
|
||||
|
||||
void Host::EndPresentFrame()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
current->hostDisplay.get()->EndPresent();
|
||||
}
|
||||
|
||||
void Host::ResizeHostDisplay(u32 new_window_width, u32 new_window_height, float new_window_scale)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
void Host::UpdateHostDisplay()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
const IConsoleWriter* PatchesCon = &ConsoleWriter_Null;
|
||||
|
||||
void LoadAllPatchesAndStuff(const Pcsx2Config& cfg)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
std::optional<u32> InputManager::ConvertHostKeyboardStringToCode(const std::string_view& str)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> InputManager::ConvertHostKeyboardCodeToString(u32 code)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
BEGIN_HOTKEY_LIST(g_host_hotkeys)
|
||||
END_HOTKEY_LIST()
|
||||
@@ -0,0 +1,147 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PCSX2GameCore.h"
|
||||
#include "common/GL/ContextAGL.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "glad.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
#if ! __has_feature(objc_arc)
|
||||
#error "Compile this with -fobjc-arc"
|
||||
#endif
|
||||
|
||||
namespace GL
|
||||
{
|
||||
ContextAGL::ContextAGL(const WindowInfo& wi)
|
||||
: Context(wi)
|
||||
{
|
||||
m_opengl_module_handle = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_NOW);
|
||||
if (!m_opengl_module_handle)
|
||||
Console.Error("Could not open OpenGL.framework, function lookups will probably fail");
|
||||
}
|
||||
|
||||
ContextAGL::~ContextAGL()
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextAGL::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try)
|
||||
{
|
||||
std::unique_ptr<ContextAGL> context = std::make_unique<ContextAGL>(wi);
|
||||
if (!context->Initialize(versions_to_try, num_versions_to_try))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
bool ContextAGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try)
|
||||
{
|
||||
MakeCurrent();
|
||||
|
||||
for (size_t i = 0; i < num_versions_to_try; i++)
|
||||
{
|
||||
const Version& cv = versions_to_try[i];
|
||||
if (cv.profile == Profile::NoProfile && CreateContext(nullptr, NSOpenGLProfileVersionLegacy, true))
|
||||
{
|
||||
// we already have the dummy context, so just use that
|
||||
m_version = cv;
|
||||
return true;
|
||||
}
|
||||
else if (cv.profile == Profile::Core)
|
||||
{
|
||||
if (cv.major_version > 4 || cv.minor_version > 1)
|
||||
continue;
|
||||
|
||||
const NSOpenGLPixelFormatAttribute profile = (cv.major_version > 3 || cv.minor_version > 2) ? NSOpenGLProfileVersion4_1Core : NSOpenGLProfileVersion3_2Core;
|
||||
if (CreateContext(nullptr, static_cast<int>(profile), true))
|
||||
{
|
||||
m_version = cv;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void* ContextAGL::GetProcAddress(const char* name)
|
||||
{
|
||||
void* addr = m_opengl_module_handle ? dlsym(m_opengl_module_handle, name) : nullptr;
|
||||
if (addr)
|
||||
return addr;
|
||||
|
||||
return dlsym(RTLD_NEXT, name);
|
||||
}
|
||||
|
||||
bool ContextAGL::ChangeSurface(const WindowInfo& new_wi)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContextAGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/)
|
||||
{
|
||||
UpdateDimensions();
|
||||
}
|
||||
|
||||
bool ContextAGL::UpdateDimensions()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextAGL::SwapBuffers()
|
||||
{
|
||||
[_current.renderDelegate didRenderFrameOnAlternateThread];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextAGL::MakeCurrent()
|
||||
{
|
||||
[_current.renderDelegate willRenderFrameOnAlternateThread];
|
||||
//SwapBuffers();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextAGL::DoneCurrent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextAGL::SetSwapInterval(s32 interval)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextAGL::CreateSharedContext(const WindowInfo& wi)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ContextAGL::CreateContext(NSOpenGLContext* share_context, int profile, bool make_current)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContextAGL::BindContextToView()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ContextAGL::CleanupView()
|
||||
{
|
||||
m_view = nullptr;
|
||||
}
|
||||
} // namespace GL
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,205 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "GSMTLDeviceInfo.h"
|
||||
|
||||
#include "common/Console.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#import "PCSX2GameCore.h"
|
||||
|
||||
static id<MTLLibrary> loadMainLibrary(id<MTLDevice> dev, NSString* name)
|
||||
{
|
||||
NSURL* path = [[NSBundle bundleForClass:[PCSX2GameCore class]] URLForResource:name withExtension:@"metallib"];
|
||||
return path ? [dev newLibraryWithURL:path error:nullptr] : nullptr;
|
||||
}
|
||||
|
||||
static MRCOwned<id<MTLLibrary>> loadMainLibrary(id<MTLDevice> dev)
|
||||
{
|
||||
if (@available(macOS 11.0, iOS 14.0, *))
|
||||
if (id<MTLLibrary> lib = loadMainLibrary(dev, @"Metal23"))
|
||||
return MRCTransfer(lib);
|
||||
if (@available(macOS 10.15, iOS 13.0, *))
|
||||
if (id<MTLLibrary> lib = loadMainLibrary(dev, @"Metal22"))
|
||||
return MRCTransfer(lib);
|
||||
if (@available(macOS 10.14, iOS 12.0, *))
|
||||
if (id<MTLLibrary> lib = loadMainLibrary(dev, @"Metal21"))
|
||||
return MRCTransfer(lib);
|
||||
return MRCTransfer([dev newDefaultLibraryWithBundle:[NSBundle bundleForClass:[PCSX2GameCore class]] error:nullptr]);
|
||||
}
|
||||
|
||||
static GSMTLDevice::MetalVersion detectLibraryVersion(id<MTLLibrary> lib)
|
||||
{
|
||||
// These functions are defined in tfx.metal to indicate the metal version used to make the metallib
|
||||
if (MRCTransfer([lib newFunctionWithName:@"metal_version_23"]))
|
||||
return GSMTLDevice::MetalVersion::Metal23;
|
||||
if (MRCTransfer([lib newFunctionWithName:@"metal_version_22"]))
|
||||
return GSMTLDevice::MetalVersion::Metal22;
|
||||
if (MRCTransfer([lib newFunctionWithName:@"metal_version_21"]))
|
||||
return GSMTLDevice::MetalVersion::Metal21;
|
||||
return GSMTLDevice::MetalVersion::Metal20;
|
||||
}
|
||||
|
||||
static bool detectPrimIDSupport(id<MTLDevice> dev, id<MTLLibrary> lib)
|
||||
{
|
||||
// Nvidia Metal driver is missing primid support, yay
|
||||
MRCOwned<MTLRenderPipelineDescriptor*> desc = MRCTransfer([MTLRenderPipelineDescriptor new]);
|
||||
[desc setVertexFunction:MRCTransfer([lib newFunctionWithName:@"fs_triangle"])];
|
||||
[desc setFragmentFunction:MRCTransfer([lib newFunctionWithName:@"primid_test"])];
|
||||
[[desc colorAttachments][0] setPixelFormat:MTLPixelFormatR8Uint];
|
||||
NSError* err;
|
||||
[[dev newRenderPipelineStateWithDescriptor:desc error:&err] release];
|
||||
return !err;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
enum class DetectionResult
|
||||
{
|
||||
HaswellOrNotIntel, ///< Everything works fine
|
||||
Broadwell, ///< PrimID broken
|
||||
Skylake, ///< PrimID broken, FBFetch supported
|
||||
};
|
||||
}
|
||||
|
||||
static DetectionResult detectIntelGPU(id<MTLDevice> dev, id<MTLLibrary> lib)
|
||||
{
|
||||
// Even though it's nowhere in the feature set tables, some Intel GPUs support fbfetch!
|
||||
// Annoyingly, the Haswell compiler successfully makes a pipeline but actually miscompiles it and doesn't insert any fbfetch instructions
|
||||
// The Broadwell compiler inserts the Skylake fbfetch instruction, but Broadwell doesn't support that. It seems to make the shader not do anything
|
||||
// So we actually have to test the thing
|
||||
// In addition, Broadwell+ has broken primid so we need to disable that.
|
||||
// Conveniently we can use the same test to detect both (except on macOS < 11. All Broadwell machines support 11, so the answer to that is "upgrade")
|
||||
// See https://github.com/tellowkrinkle/MetalBugReproduction/releases/tag/BrokenPrimID for details
|
||||
|
||||
// AMD compiler crashes and gets retried 3 times over multiple seconds trying to compile the pipeline
|
||||
// We know this is only a possibility on Intel anyways
|
||||
if (![[dev name] containsString:@"Intel"])
|
||||
return DetectionResult::HaswellOrNotIntel;
|
||||
auto pdesc = MRCTransfer([MTLRenderPipelineDescriptor new]);
|
||||
[pdesc setVertexFunction:MRCTransfer([lib newFunctionWithName:@"fs_triangle"])];
|
||||
[pdesc setFragmentFunction:MRCTransfer([lib newFunctionWithName:@"fbfetch_test"])];
|
||||
[[pdesc colorAttachments][0] setPixelFormat:MTLPixelFormatRGBA8Unorm];
|
||||
auto pipe = MRCTransfer([dev newRenderPipelineStateWithDescriptor:pdesc error:nil]);
|
||||
if (!pipe)
|
||||
return DetectionResult::HaswellOrNotIntel;
|
||||
auto buf = MRCTransfer([dev newBufferWithLength:4 options:MTLResourceStorageModeShared]);
|
||||
auto tdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm width:1 height:1 mipmapped:false];
|
||||
[tdesc setUsage:MTLTextureUsageRenderTarget];
|
||||
auto tex = MRCTransfer([dev newTextureWithDescriptor:tdesc]);
|
||||
auto q = MRCTransfer([dev newCommandQueue]);
|
||||
u32 px = 0x11223344;
|
||||
memcpy([buf contents], &px, 4);
|
||||
id<MTLCommandBuffer> cmdbuf = [q commandBuffer];
|
||||
id<MTLBlitCommandEncoder> upload = [cmdbuf blitCommandEncoder];
|
||||
[upload copyFromBuffer:buf sourceOffset:0 sourceBytesPerRow:4 sourceBytesPerImage:4 sourceSize:MTLSizeMake(1, 1, 1) toTexture:tex destinationSlice:0 destinationLevel:0 destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
[upload endEncoding];
|
||||
auto rpdesc = MRCTransfer([MTLRenderPassDescriptor new]);
|
||||
[[rpdesc colorAttachments][0] setTexture:tex];
|
||||
[[rpdesc colorAttachments][0] setLoadAction:MTLLoadActionLoad];
|
||||
[[rpdesc colorAttachments][0] setStoreAction:MTLStoreActionStore];
|
||||
id<MTLRenderCommandEncoder> renc = [cmdbuf renderCommandEncoderWithDescriptor:rpdesc];
|
||||
[renc setRenderPipelineState:pipe];
|
||||
[renc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
|
||||
[renc endEncoding];
|
||||
id<MTLBlitCommandEncoder> download = [cmdbuf blitCommandEncoder];
|
||||
[download copyFromTexture:tex sourceSlice:0 sourceLevel:0 sourceOrigin:MTLOriginMake(0, 0, 0) sourceSize:MTLSizeMake(1, 1, 1) toBuffer:buf destinationOffset:0 destinationBytesPerRow:4 destinationBytesPerImage:4];
|
||||
[download endEncoding];
|
||||
[cmdbuf commit];
|
||||
[cmdbuf waitUntilCompleted];
|
||||
u32 outpx;
|
||||
memcpy(&outpx, [buf contents], 4);
|
||||
// Proper fbfetch will double contents, Haswell will return black, and Broadwell will do nothing
|
||||
if (outpx == 0x22446688)
|
||||
return DetectionResult::Skylake;
|
||||
else if (outpx == 0x11223344)
|
||||
return DetectionResult::Broadwell;
|
||||
else
|
||||
return DetectionResult::HaswellOrNotIntel;
|
||||
}
|
||||
|
||||
GSMTLDevice::GSMTLDevice(MRCOwned<id<MTLDevice>> dev)
|
||||
{
|
||||
if (!dev)
|
||||
return;
|
||||
shaders = loadMainLibrary(dev);
|
||||
|
||||
memset(&features, 0, sizeof(features));
|
||||
|
||||
if (char* env = getenv("MTL_UNIFIED_MEMORY"))
|
||||
features.unified_memory = env[0] == '1' || env[0] == 'y' || env[0] == 'Y';
|
||||
else if (@available(macOS 10.15, iOS 13.0, *))
|
||||
features.unified_memory = [dev hasUnifiedMemory];
|
||||
else
|
||||
features.unified_memory = false;
|
||||
|
||||
if (@available(macOS 10.15, iOS 13.0, *))
|
||||
if ([dev supportsFamily:MTLGPUFamilyMac2] || [dev supportsFamily:MTLGPUFamilyApple1])
|
||||
features.texture_swizzle = true;
|
||||
|
||||
if (@available(macOS 11.0, iOS 13.0, *))
|
||||
if ([dev supportsFamily:MTLGPUFamilyApple1])
|
||||
features.framebuffer_fetch = true;
|
||||
|
||||
features.shader_version = detectLibraryVersion(shaders);
|
||||
if (features.framebuffer_fetch && features.shader_version < MetalVersion::Metal23)
|
||||
{
|
||||
Console.Warning("Metal: GPU supports framebuffer fetch but shader lib does not! Get an updated shader lib for better performance!");
|
||||
features.framebuffer_fetch = false;
|
||||
}
|
||||
|
||||
features.primid = features.shader_version >= MetalVersion::Metal22;
|
||||
if (features.primid && !detectPrimIDSupport(dev, shaders))
|
||||
features.primid = false;
|
||||
|
||||
if (!features.framebuffer_fetch && features.shader_version >= MetalVersion::Metal23)
|
||||
{
|
||||
switch (detectIntelGPU(dev, shaders))
|
||||
{
|
||||
case DetectionResult::HaswellOrNotIntel:
|
||||
break;
|
||||
case DetectionResult::Broadwell:
|
||||
features.primid = false; // Broken
|
||||
break;
|
||||
case DetectionResult::Skylake:
|
||||
features.primid = false; // Broken
|
||||
features.framebuffer_fetch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
features.max_texsize = 8192;
|
||||
if ([dev supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1])
|
||||
features.max_texsize = 16384;
|
||||
if (@available(macOS 10.15, iOS 13.0, *))
|
||||
if ([dev supportsFamily:MTLGPUFamilyApple3])
|
||||
features.max_texsize = 16384;
|
||||
|
||||
this->dev = std::move(dev);
|
||||
}
|
||||
|
||||
const char* to_string(GSMTLDevice::MetalVersion ver)
|
||||
{
|
||||
switch (ver)
|
||||
{
|
||||
case GSMTLDevice::MetalVersion::Metal20: return "Metal 2.0";
|
||||
case GSMTLDevice::MetalVersion::Metal21: return "Metal 2.1";
|
||||
case GSMTLDevice::MetalVersion::Metal22: return "Metal 2.2";
|
||||
case GSMTLDevice::MetalVersion::Metal23: return "Metal 2.3";
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
@@ -0,0 +1,398 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "MetalHostDisplay.h"
|
||||
#include "GS/Renderers/Metal/GSMetalCPPAccessible.h"
|
||||
#include "GS/Renderers/Metal/GSDeviceMTL.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
class MetalHostDisplayTexture final : public HostDisplayTexture
|
||||
{
|
||||
MRCOwned<id<MTLTexture>> m_tex;
|
||||
u32 m_width, m_height;
|
||||
public:
|
||||
MetalHostDisplayTexture(MRCOwned<id<MTLTexture>> tex, u32 width, u32 height)
|
||||
: m_tex(std::move(tex))
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
{
|
||||
}
|
||||
|
||||
void* GetHandle() const override { return (__bridge void*)m_tex; };
|
||||
u32 GetWidth() const override { return m_width; }
|
||||
u32 GetHeight() const override { return m_height; }
|
||||
};
|
||||
|
||||
HostDisplay* MakeMetalHostDisplay()
|
||||
{
|
||||
return new MetalHostDisplay();
|
||||
}
|
||||
|
||||
MetalHostDisplay::MetalHostDisplay()
|
||||
: m_gpu_work_sema(dispatch_semaphore_create(3))
|
||||
{
|
||||
}
|
||||
|
||||
MetalHostDisplay::~MetalHostDisplay()
|
||||
{
|
||||
dispatch_release(m_gpu_work_sema);
|
||||
}
|
||||
|
||||
HostDisplay::AdapterAndModeList GetMetalAdapterAndModeList()
|
||||
{ @autoreleasepool {
|
||||
HostDisplay::AdapterAndModeList list;
|
||||
auto devs = MRCTransfer(MTLCopyAllDevices());
|
||||
for (id<MTLDevice> dev in devs.Get())
|
||||
list.adapter_names.push_back([[dev name] UTF8String]);
|
||||
return list;
|
||||
}}
|
||||
|
||||
template <typename Fn>
|
||||
static void OnMainThread(Fn&& fn)
|
||||
{
|
||||
if ([NSThread isMainThread])
|
||||
fn();
|
||||
else
|
||||
dispatch_sync(dispatch_get_main_queue(), fn);
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI MetalHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return RenderAPI::Metal;
|
||||
}
|
||||
|
||||
void* MetalHostDisplay::GetRenderDevice() const { return const_cast<void*>(static_cast<const void*>(&m_dev)); }
|
||||
void* MetalHostDisplay::GetRenderContext() const { return (__bridge void*)m_queue; }
|
||||
void* MetalHostDisplay::GetRenderSurface() const { return (__bridge void*)m_layer; }
|
||||
bool MetalHostDisplay::HasRenderDevice() const { return m_dev.IsOk(); }
|
||||
bool MetalHostDisplay::HasRenderSurface() const { return static_cast<bool>(m_layer);}
|
||||
|
||||
void MetalHostDisplay::AttachSurfaceOnMainThread()
|
||||
{
|
||||
ASSERT([NSThread isMainThread]);
|
||||
m_view = MRCRetain((__bridge NSView*)m_window_info.window_handle);
|
||||
[m_view setWantsLayer:YES];
|
||||
[m_view setLayer:m_layer];
|
||||
}
|
||||
|
||||
void MetalHostDisplay::DetachSurfaceOnMainThread()
|
||||
{
|
||||
ASSERT([NSThread isMainThread]);
|
||||
[m_view setLayer:nullptr];
|
||||
[m_view setWantsLayer:NO];
|
||||
m_view = nullptr;
|
||||
}
|
||||
|
||||
bool MetalHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device)
|
||||
{ @autoreleasepool {
|
||||
m_window_info = wi;
|
||||
pxAssertRel(!m_dev.dev, "Device already created!");
|
||||
std::string null_terminated_adapter_name(adapter_name);
|
||||
NSString* ns_adapter_name = [NSString stringWithUTF8String:null_terminated_adapter_name.c_str()];
|
||||
auto devs = MRCTransfer(MTLCopyAllDevices());
|
||||
for (id<MTLDevice> dev in devs.Get())
|
||||
{
|
||||
if ([[dev name] isEqualToString:ns_adapter_name])
|
||||
m_dev = GSMTLDevice(MRCRetain(dev));
|
||||
}
|
||||
if (!m_dev.dev)
|
||||
{
|
||||
if (adapter_name != "Default Adapter")
|
||||
Console.Warning("Metal: Couldn't find adapter %s, using default", null_terminated_adapter_name.c_str());
|
||||
m_dev = GSMTLDevice(MRCTransfer(MTLCreateSystemDefaultDevice()));
|
||||
}
|
||||
m_queue = MRCTransfer([m_dev.dev newCommandQueue]);
|
||||
|
||||
m_pass_desc = MRCTransfer([MTLRenderPassDescriptor new]);
|
||||
[m_pass_desc colorAttachments][0].loadAction = MTLLoadActionClear;
|
||||
[m_pass_desc colorAttachments][0].clearColor = MTLClearColorMake(0, 0, 0, 0);
|
||||
[m_pass_desc colorAttachments][0].storeAction = MTLStoreActionStore;
|
||||
|
||||
m_capture_start_frame = 0;
|
||||
if (char* env = getenv("MTL_CAPTURE"))
|
||||
{
|
||||
m_capture_start_frame = atoi(env);
|
||||
}
|
||||
if (m_capture_start_frame)
|
||||
{
|
||||
Console.WriteLn("Metal will capture frame %u", m_capture_start_frame);
|
||||
}
|
||||
|
||||
if (m_dev.IsOk() && m_queue)
|
||||
{
|
||||
Console.WriteLn("Renderer info:\n %s", GetDriverInfo().c_str());
|
||||
OnMainThread([this]
|
||||
{
|
||||
m_layer = MRCRetain([CAMetalLayer layer]);
|
||||
[m_layer setDrawableSize:CGSizeMake(m_window_info.surface_width, m_window_info.surface_height)];
|
||||
[m_layer setDevice:m_dev.dev];
|
||||
AttachSurfaceOnMainThread();
|
||||
});
|
||||
SetVSync(vsync);
|
||||
m_drawable_fetcher.Start(m_layer);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}}
|
||||
|
||||
bool MetalHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetalHostDisplay::MakeRenderContextCurrent() { return true; }
|
||||
bool MetalHostDisplay::DoneRenderContextCurrent() { return true; }
|
||||
|
||||
void MetalHostDisplay::DestroyRenderDevice()
|
||||
{
|
||||
DestroyRenderSurface();
|
||||
m_queue = nullptr;
|
||||
m_dev.Reset();
|
||||
}
|
||||
|
||||
void MetalHostDisplay::DestroyRenderSurface()
|
||||
{
|
||||
if (!m_layer)
|
||||
return;
|
||||
m_drawable_fetcher.Stop();
|
||||
OnMainThread([this]{ DetachSurfaceOnMainThread(); });
|
||||
m_layer = nullptr;
|
||||
}
|
||||
|
||||
bool MetalHostDisplay::ChangeRenderWindow(const WindowInfo& wi)
|
||||
{
|
||||
OnMainThread([this, &wi]
|
||||
{
|
||||
DetachSurfaceOnMainThread();
|
||||
m_window_info = wi;
|
||||
AttachSurfaceOnMainThread();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetalHostDisplay::SupportsFullscreen() const { return false; }
|
||||
bool MetalHostDisplay::IsFullscreen() { return false; }
|
||||
bool MetalHostDisplay::SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) { return false; }
|
||||
|
||||
HostDisplay::AdapterAndModeList MetalHostDisplay::GetAdapterAndModeList()
|
||||
{
|
||||
return GetMetalAdapterAndModeList();
|
||||
}
|
||||
|
||||
std::string MetalHostDisplay::GetDriverInfo() const
|
||||
{ @autoreleasepool {
|
||||
std::string desc([[m_dev.dev description] UTF8String]);
|
||||
desc += "\n Texture Swizzle: " + std::string(m_dev.features.texture_swizzle ? "Supported" : "Unsupported");
|
||||
desc += "\n Unified Memory: " + std::string(m_dev.features.unified_memory ? "Supported" : "Unsupported");
|
||||
desc += "\n Framebuffer Fetch: " + std::string(m_dev.features.framebuffer_fetch ? "Supported" : "Unsupported");
|
||||
desc += "\n Primitive ID: " + std::string(m_dev.features.primid ? "Supported" : "Unsupported");
|
||||
desc += "\n Shader Version: " + std::string(to_string(m_dev.features.shader_version));
|
||||
desc += "\n Max Texture Size: " + std::to_string(m_dev.features.max_texsize);
|
||||
return desc;
|
||||
}}
|
||||
|
||||
void MetalHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
|
||||
{
|
||||
m_window_info.surface_scale = new_window_scale;
|
||||
if (m_window_info.surface_width == static_cast<u32>(new_window_width) && m_window_info.surface_height == static_cast<u32>(new_window_height))
|
||||
return;
|
||||
m_window_info.surface_width = new_window_width;
|
||||
m_window_info.surface_height = new_window_height;
|
||||
@autoreleasepool
|
||||
{
|
||||
[m_layer setDrawableSize:CGSizeMake(new_window_width, new_window_height)];
|
||||
m_drawable_fetcher.GetIfAvailable(); // Throw away the last drawable of the old size
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> MetalHostDisplay::CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic)
|
||||
{ @autoreleasepool {
|
||||
MTLTextureDescriptor* desc = [MTLTextureDescriptor
|
||||
texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
|
||||
width:width
|
||||
height:height
|
||||
mipmapped:false];
|
||||
[desc setUsage:MTLTextureUsageShaderRead];
|
||||
[desc setStorageMode:MTLStorageModePrivate];
|
||||
MRCOwned<id<MTLTexture>> tex = MRCTransfer([m_dev.dev newTextureWithDescriptor:desc]);
|
||||
if (!tex)
|
||||
return nullptr; // Something broke yay
|
||||
[tex setLabel:@"MetalHostDisplay Texture"];
|
||||
if (data)
|
||||
UpdateTexture(tex, 0, 0, width, height, data, data_stride);
|
||||
return std::make_unique<MetalHostDisplayTexture>(std::move(tex), width, height);
|
||||
}}
|
||||
|
||||
void MetalHostDisplay::UpdateTexture(id<MTLTexture> texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride)
|
||||
{
|
||||
id<MTLCommandBuffer> cmdbuf = [m_queue commandBuffer];
|
||||
id<MTLBlitCommandEncoder> enc = [cmdbuf blitCommandEncoder];
|
||||
size_t bytes = data_stride * height;
|
||||
MRCOwned<id<MTLBuffer>> buf = MRCTransfer([m_dev.dev newBufferWithLength:bytes options:MTLResourceStorageModeShared | MTLResourceCPUCacheModeWriteCombined]);
|
||||
memcpy([buf contents], data, bytes);
|
||||
[enc copyFromBuffer:buf
|
||||
sourceOffset:0
|
||||
sourceBytesPerRow:data_stride
|
||||
sourceBytesPerImage:bytes
|
||||
sourceSize:MTLSizeMake(width, height, 1)
|
||||
toTexture:texture
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
[enc endEncoding];
|
||||
[cmdbuf commit];
|
||||
}
|
||||
|
||||
void MetalHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride)
|
||||
{ @autoreleasepool {
|
||||
UpdateTexture((__bridge id<MTLTexture>)texture->GetHandle(), x, y, width, height, data, data_stride);
|
||||
}}
|
||||
|
||||
static bool s_capture_next = false;
|
||||
|
||||
bool MetalHostDisplay::BeginPresent(bool frame_skip)
|
||||
{ @autoreleasepool {
|
||||
GSDeviceMTL* dev = static_cast<GSDeviceMTL*>(g_gs_device.get());
|
||||
if (dev && m_capture_start_frame && dev->FrameNo() == m_capture_start_frame)
|
||||
s_capture_next = true;
|
||||
if (frame_skip || m_window_info.type == WindowInfo::Type::Surfaceless || !g_gs_device)
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
id<MTLCommandBuffer> buf = dev->GetRenderCmdBuf();
|
||||
// TODO: Use synchronous fetch if vsync is enabled
|
||||
dispatch_semaphore_wait(m_gpu_work_sema, DISPATCH_TIME_FOREVER);
|
||||
dispatch_retain(m_gpu_work_sema);
|
||||
[buf addCompletedHandler:[sema = m_gpu_work_sema](id<MTLCommandBuffer>){ dispatch_semaphore_signal(sema); dispatch_release(sema); }];
|
||||
m_current_drawable = m_drawable_fetcher.GetIfAvailable();
|
||||
dev->EndRenderPass();
|
||||
if (!m_current_drawable)
|
||||
{
|
||||
[buf pushDebugGroup:@"Present Skipped"];
|
||||
[buf popDebugGroup];
|
||||
dev->FlushEncoders();
|
||||
|
||||
return false;
|
||||
}
|
||||
[m_pass_desc colorAttachments][0].texture = [m_current_drawable texture];
|
||||
id<MTLRenderCommandEncoder> enc = [buf renderCommandEncoderWithDescriptor:m_pass_desc];
|
||||
[enc setLabel:@"Present"];
|
||||
dev->m_current_render.encoder = MRCRetain(enc);
|
||||
return true;
|
||||
}}
|
||||
|
||||
void MetalHostDisplay::EndPresent()
|
||||
{ @autoreleasepool {
|
||||
GSDeviceMTL* dev = static_cast<GSDeviceMTL*>(g_gs_device.get());
|
||||
pxAssertDev(dev && dev->m_current_render.encoder && dev->m_current_render_cmdbuf, "BeginPresent cmdbuf was destroyed");
|
||||
|
||||
dev->EndRenderPass();
|
||||
if (m_current_drawable)
|
||||
[dev->GetRenderCmdBuf() presentDrawable:m_current_drawable];
|
||||
dev->FlushEncoders();
|
||||
m_current_drawable = nullptr;
|
||||
if (m_capture_start_frame)
|
||||
{
|
||||
if (@available(macOS 10.15, iOS 13, *))
|
||||
{
|
||||
static NSString* const path = @"/tmp/PCSX2MTLCapture.gputrace";
|
||||
static u32 frames;
|
||||
if (frames)
|
||||
{
|
||||
--frames;
|
||||
if (!frames)
|
||||
{
|
||||
[[MTLCaptureManager sharedCaptureManager] stopCapture];
|
||||
Console.WriteLn("Metal Trace Capture to /tmp/PCSX2MTLCapture.gputrace finished");
|
||||
[[NSWorkspace sharedWorkspace] selectFile:path
|
||||
inFileViewerRootedAtPath:@"/tmp/"];
|
||||
}
|
||||
}
|
||||
else if (s_capture_next)
|
||||
{
|
||||
s_capture_next = false;
|
||||
MTLCaptureManager* mgr = [MTLCaptureManager sharedCaptureManager];
|
||||
if ([mgr supportsDestination:MTLCaptureDestinationGPUTraceDocument])
|
||||
{
|
||||
MTLCaptureDescriptor* desc = [[MTLCaptureDescriptor new] autorelease];
|
||||
[desc setCaptureObject:m_dev.dev];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:path])
|
||||
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
|
||||
[desc setOutputURL:[NSURL fileURLWithPath:path]];
|
||||
[desc setDestination:MTLCaptureDestinationGPUTraceDocument];
|
||||
NSError* err = nullptr;
|
||||
[mgr startCaptureWithDescriptor:desc error:&err];
|
||||
if (err)
|
||||
{
|
||||
Console.Error("Metal Trace Capture failed: %s", [[err localizedDescription] UTF8String]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLn("Metal Trace Capture to /tmp/PCSX2MTLCapture.gputrace started");
|
||||
frames = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("Metal Trace Capture Failed: MTLCaptureManager doesn't support GPU trace documents! (Did you forget to run with METAL_CAPTURE_ENABLED=1?)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
void MetalHostDisplay::SetVSync(VsyncMode mode)
|
||||
{
|
||||
[m_layer setDisplaySyncEnabled:mode != VsyncMode::Off];
|
||||
m_vsync_mode = mode;
|
||||
}
|
||||
|
||||
bool MetalHostDisplay::CreateImGuiContext()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void MetalHostDisplay::DestroyImGuiContext()
|
||||
{
|
||||
}
|
||||
|
||||
bool MetalHostDisplay::UpdateImGuiFontTexture()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetalHostDisplay::GetHostRefreshRate(float* refresh_rate)
|
||||
{
|
||||
OnMainThread([this, refresh_rate]
|
||||
{
|
||||
u32 did = [[[[[m_view window] screen] deviceDescription] valueForKey:@"NSScreenNumber"] unsignedIntValue];
|
||||
if (CGDisplayModeRef mode = CGDisplayCopyDisplayMode(did))
|
||||
{
|
||||
*refresh_rate = CGDisplayModeGetRefreshRate(mode);
|
||||
CGDisplayModeRelease(mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
*refresh_rate = 0;
|
||||
}
|
||||
});
|
||||
return *refresh_rate != 0;
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
@@ -0,0 +1,372 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "OpenGLHostDisplay.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/ScopedGuard.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/GL/Program.h"
|
||||
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
|
||||
class OpenGLHostDisplayTexture : public HostDisplayTexture
|
||||
{
|
||||
public:
|
||||
OpenGLHostDisplayTexture(GLuint texture, u32 width, u32 height)
|
||||
: m_texture(texture)
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
{
|
||||
}
|
||||
~OpenGLHostDisplayTexture() override = default;
|
||||
|
||||
void* GetHandle() const override { return reinterpret_cast<void*>(static_cast<uintptr_t>(m_texture)); }
|
||||
u32 GetWidth() const override { return m_width; }
|
||||
u32 GetHeight() const override { return m_height; }
|
||||
|
||||
GLuint GetGLID() const { return m_texture; }
|
||||
|
||||
private:
|
||||
GLuint m_texture;
|
||||
u32 m_width;
|
||||
u32 m_height;
|
||||
u32 m_layers;
|
||||
u32 m_levels;
|
||||
};
|
||||
|
||||
OpenGLHostDisplay::OpenGLHostDisplay() = default;
|
||||
|
||||
OpenGLHostDisplay::~OpenGLHostDisplay()
|
||||
{
|
||||
pxAssertMsg(!m_gl_context, "Context should have been destroyed by now");
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL;
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_gl_context.get();
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderSurface() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic /* = false */)
|
||||
{
|
||||
// clear error
|
||||
glGetError();
|
||||
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
|
||||
if ((GLAD_GL_ARB_texture_storage || GLAD_GL_ES_VERSION_3_0) && !data)
|
||||
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
|
||||
else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
GLenum error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
{
|
||||
Console.Error("Failed to create texture: 0x%X", error);
|
||||
glDeleteTextures(1, &id);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<OpenGLHostDisplayTexture>(id, width, height);
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data, u32 texture_data_stride)
|
||||
{
|
||||
OpenGLHostDisplayTexture* tex = static_cast<OpenGLHostDisplayTexture*>(texture);
|
||||
|
||||
GLint alignment;
|
||||
if (texture_data_stride & 1)
|
||||
alignment = 1;
|
||||
else if (texture_data_stride & 2)
|
||||
alignment = 2;
|
||||
else
|
||||
alignment = 4;
|
||||
|
||||
GLint old_texture_binding = 0, old_alignment = 0, old_row_length = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->GetGLID());
|
||||
|
||||
glGetIntegerv(GL_UNPACK_ALIGNMENT, &old_alignment);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
|
||||
|
||||
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &old_row_length);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture_data_stride / sizeof(u32));
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA8, GL_UNSIGNED_BYTE, texture_data);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, old_row_length);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, old_alignment);
|
||||
glBindTexture(GL_TEXTURE_2D, old_texture_binding);
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::SetVSync(VsyncMode mode)
|
||||
{
|
||||
if (m_gl_context->GetWindowInfo().type == WindowInfo::Type::Surfaceless)
|
||||
return;
|
||||
|
||||
// Window framebuffer has to be bound to call SetSwapInterval.
|
||||
GLint current_fbo = 0;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
||||
if (mode != VsyncMode::Adaptive || !m_gl_context->SetSwapInterval(-1))
|
||||
m_gl_context->SetSwapInterval(static_cast<s32>(mode != VsyncMode::Off));
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo);
|
||||
}
|
||||
|
||||
const char* OpenGLHostDisplay::GetGLSLVersionString() const
|
||||
{
|
||||
if (GetRenderAPI() == RenderAPI::OpenGLES)
|
||||
{
|
||||
if (GLAD_GL_ES_VERSION_3_0)
|
||||
return "#version 300 es";
|
||||
else
|
||||
return "#version 100";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GLAD_GL_VERSION_3_3)
|
||||
return "#version 330";
|
||||
else
|
||||
return "#version 130";
|
||||
}
|
||||
}
|
||||
|
||||
std::string OpenGLHostDisplay::GetGLSLVersionHeader() const
|
||||
{
|
||||
std::string header = GetGLSLVersionString();
|
||||
header += "\n\n";
|
||||
if (GetRenderAPI() == RenderAPI::OpenGLES)
|
||||
{
|
||||
header += "precision highp float;\n";
|
||||
header += "precision highp int;\n\n";
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::HasRenderDevice() const
|
||||
{
|
||||
return static_cast<bool>(m_gl_context);
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::HasRenderSurface() const
|
||||
{
|
||||
return m_window_info.type != WindowInfo::Type::Surfaceless;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device)
|
||||
{
|
||||
m_gl_context = GL::Context::Create(wi);
|
||||
if (!m_gl_context)
|
||||
{
|
||||
Console.Error("Failed to create any GL context");
|
||||
m_gl_context.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_info = m_gl_context->GetWindowInfo();
|
||||
m_vsync_mode = vsync;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
SetSwapInterval();
|
||||
GL::Program::ResetLastProgram();
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::SetSwapInterval()
|
||||
{
|
||||
const int interval = ((m_vsync_mode == VsyncMode::Adaptive) ? -1 : ((m_vsync_mode == VsyncMode::On) ? 1 : 0));
|
||||
m_gl_context->SetSwapInterval(interval);
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::MakeRenderContextCurrent()
|
||||
{
|
||||
if (!m_gl_context->MakeCurrent())
|
||||
{
|
||||
Console.Error("Failed to make GL context current");
|
||||
return false;
|
||||
}
|
||||
|
||||
SetSwapInterval();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::DoneRenderContextCurrent()
|
||||
{
|
||||
return m_gl_context->DoneCurrent();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::DestroyRenderDevice()
|
||||
{
|
||||
if (!m_gl_context)
|
||||
return;
|
||||
|
||||
m_gl_context->DoneCurrent();
|
||||
m_gl_context.reset();
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||
{
|
||||
pxAssert(m_gl_context);
|
||||
|
||||
if (!m_gl_context->ChangeSurface(new_wi))
|
||||
{
|
||||
Console.Error("Failed to change surface");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_info = m_gl_context->GetWindowInfo();
|
||||
|
||||
if (new_wi.type != WindowInfo::Type::Surfaceless)
|
||||
{
|
||||
// reset vsync rate, since it (usually) gets lost
|
||||
if (m_vsync_mode != VsyncMode::Adaptive || !m_gl_context->SetSwapInterval(-1))
|
||||
m_gl_context->SetSwapInterval(static_cast<s32>(m_vsync_mode != VsyncMode::Off));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
|
||||
{
|
||||
if (!m_gl_context)
|
||||
return;
|
||||
|
||||
m_window_info.surface_scale = new_window_scale;
|
||||
if (m_window_info.surface_width == static_cast<u32>(new_window_width) &&
|
||||
m_window_info.surface_height == static_cast<u32>(new_window_height))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||
m_window_info = m_gl_context->GetWindowInfo();
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::SupportsFullscreen() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::IsFullscreen()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HostDisplay::AdapterAndModeList OpenGLHostDisplay::GetAdapterAndModeList()
|
||||
{
|
||||
AdapterAndModeList aml;
|
||||
|
||||
if (m_gl_context)
|
||||
{
|
||||
for (const GL::Context::FullscreenModeInfo& fmi : m_gl_context->EnumerateFullscreenModes())
|
||||
aml.fullscreen_modes.push_back(GetFullscreenModeString(fmi.width, fmi.height, fmi.refresh_rate));
|
||||
}
|
||||
|
||||
return aml;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::DestroyRenderSurface()
|
||||
{
|
||||
if (!m_gl_context)
|
||||
return;
|
||||
|
||||
m_window_info = {};
|
||||
if (!m_gl_context->ChangeSurface(m_window_info))
|
||||
Console.Error("Failed to switch to surfaceless");
|
||||
}
|
||||
|
||||
std::string OpenGLHostDisplay::GetDriverInfo() const
|
||||
{
|
||||
const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
const char* gl_renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
||||
const char* gl_version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
||||
return StringUtil::StdStringFromFormat(
|
||||
"%s Context:\n%s\n%s %s", m_gl_context->IsGLES() ? "OpenGL ES" : "OpenGL", gl_version, gl_vendor, gl_renderer);
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::CreateImGuiContext()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::DestroyImGuiContext()
|
||||
{
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::UpdateImGuiFontTexture()
|
||||
{
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::BeginPresent(bool frame_skip)
|
||||
{
|
||||
if (frame_skip || m_window_info.type == WindowInfo::Type::Surfaceless)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 1);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glViewport(0, 0, m_window_info.surface_width, m_window_info.surface_height);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::EndPresent()
|
||||
{
|
||||
// clear out pipeline bindings, since imgui doesn't use them
|
||||
glBindProgramPipeline(0);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
GL::Program::ResetLastProgram();
|
||||
|
||||
m_gl_context->SwapBuffers();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2021, OpenEmu Team
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the OpenEmu Team nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef soundtouch_config_h
|
||||
#define soundtouch_config_h
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define SOUNDTOUCH_ALLOW_SSE
|
||||
#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
||||
#endif
|
||||
|
||||
#endif /* soundtouch_config_h */
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2021, OpenEmu Team
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the OpenEmu Team nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef svnrev_h
|
||||
#define svnrev_h
|
||||
|
||||
#define SVN_MODS 1
|
||||
#define SVN_REV 999ll
|
||||
|
||||
#endif /* svnrev_h */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>PCSX2</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>OEGameCoreController</string>
|
||||
<key>OEGameCoreClass</key>
|
||||
<string>PCSX2GameCore</string>
|
||||
<key>OEGameCoreOptions</key>
|
||||
<dict>
|
||||
<key>openemu.system.ps2</key>
|
||||
<dict>
|
||||
<key>OEGameCoreHasGlitches</key>
|
||||
<true/>
|
||||
<key>OEGameCoreSaveStatesNotSupported</key>
|
||||
<true/>
|
||||
<key>OEGameCoreSupportsCheatCode</key>
|
||||
<false/>
|
||||
<key>OEGameCoreSupportsMultipleDiscs</key>
|
||||
<true/>
|
||||
<key>OERequiredFiles</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Description</key>
|
||||
<string>PlayStation 2 SCPH-10000 (v1.0 Japan) BIOS</string>
|
||||
<key>MD5</key>
|
||||
<string>acf4730ceb38ac9d8c7d8e21f2614600</string>
|
||||
<key>Name</key>
|
||||
<string>scph10000.bin</string>
|
||||
<key>Size</key>
|
||||
<real>4194304</real>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Description</key>
|
||||
<string>PlayStation 2 SCPH-39001 (v1.60 USA) BIOS</string>
|
||||
<key>MD5</key>
|
||||
<string>d5ce2c7d119f563ce04bc04dbc3a323e</string>
|
||||
<key>Name</key>
|
||||
<string>scph39001.bin</string>
|
||||
<key>Size</key>
|
||||
<real>4194304</real>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Description</key>
|
||||
<string>PlayStation 2 SCPH-70004 (v2.0 Europe) BIOS</string>
|
||||
<key>MD5</key>
|
||||
<string>dc752f160044f2ed5fc1f4964db2a095</string>
|
||||
<key>Name</key>
|
||||
<string>scph70004.bin</string>
|
||||
<key>Size</key>
|
||||
<real>4194304</real>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>OEGameCorePlayerCount</key>
|
||||
<string>1</string>
|
||||
<key>OEProjectURL</key>
|
||||
<string>https://pcsx2.net</string>
|
||||
<key>OESystemIdentifiers</key>
|
||||
<array>
|
||||
<string>openemu.system.ps2</string>
|
||||
</array>
|
||||
<key>SUEnableAutomaticChecks</key>
|
||||
<false/>
|
||||
<key>SUFeedURL</key>
|
||||
<string>https://raw.github.com/OpenEmu/OpenEmu-Update/master/pcsx2_appcast.xml</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,183 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: affinematrix2d.cpp
|
||||
// Purpose: implementation of wxAffineMatrix2D
|
||||
// Author: Based on wxTransformMatrix by Chris Breeze, Julian Smart
|
||||
// Created: 2011-04-05
|
||||
// Copyright: (c) wxWidgets team
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_GEOMETRY
|
||||
|
||||
#include "wx/affinematrix2d.h"
|
||||
#include "wx/math.h"
|
||||
|
||||
// sets the matrix to the respective values
|
||||
void wxAffineMatrix2D::Set(const wxMatrix2D &mat2D, const wxPoint2DDouble &tr)
|
||||
{
|
||||
m_11 = mat2D.m_11;
|
||||
m_12 = mat2D.m_12;
|
||||
m_21 = mat2D.m_21;
|
||||
m_22 = mat2D.m_22;
|
||||
m_tx = tr.m_x;
|
||||
m_ty = tr.m_y;
|
||||
}
|
||||
|
||||
// gets the component valuess of the matrix
|
||||
void wxAffineMatrix2D::Get(wxMatrix2D *mat2D, wxPoint2DDouble *tr) const
|
||||
{
|
||||
mat2D->m_11 = m_11;
|
||||
mat2D->m_12 = m_12;
|
||||
mat2D->m_21 = m_21;
|
||||
mat2D->m_22 = m_22;
|
||||
|
||||
if ( tr )
|
||||
{
|
||||
tr->m_x = m_tx;
|
||||
tr->m_y = m_ty;
|
||||
}
|
||||
}
|
||||
|
||||
// concatenates the matrix
|
||||
// | t.m_11 t.m_12 0 | | m_11 m_12 0 |
|
||||
// | t.m_21 t.m_22 0 | x | m_21 m_22 0 |
|
||||
// | t.m_tx t.m_ty 1 | | m_tx m_ty 1 |
|
||||
void wxAffineMatrix2D::Concat(const wxAffineMatrix2DBase &t)
|
||||
{
|
||||
wxMatrix2D mat;
|
||||
wxPoint2DDouble tr;
|
||||
t.Get(&mat, &tr);
|
||||
|
||||
m_tx += tr.m_x*m_11 + tr.m_y*m_21;
|
||||
m_ty += tr.m_x*m_12 + tr.m_y*m_22;
|
||||
wxDouble e11 = mat.m_11*m_11 + mat.m_12*m_21;
|
||||
wxDouble e12 = mat.m_11*m_12 + mat.m_12*m_22;
|
||||
wxDouble e21 = mat.m_21*m_11 + mat.m_22*m_21;
|
||||
m_22 = mat.m_21*m_12 + mat.m_22*m_22;
|
||||
m_11 = e11;
|
||||
m_12 = e12;
|
||||
m_21 = e21;
|
||||
}
|
||||
|
||||
// makes this its inverse matrix.
|
||||
// Invert
|
||||
// | m_11 m_12 0 |
|
||||
// | m_21 m_22 0 |
|
||||
// | m_tx m_ty 1 |
|
||||
bool wxAffineMatrix2D::Invert()
|
||||
{
|
||||
const wxDouble det = m_11*m_22 - m_12*m_21;
|
||||
|
||||
if ( !det )
|
||||
return false;
|
||||
|
||||
wxDouble ex = (m_21*m_ty - m_22*m_tx) / det;
|
||||
m_ty = (-m_11*m_ty + m_12*m_tx) / det;
|
||||
m_tx = ex;
|
||||
wxDouble e11 = m_22 / det;
|
||||
m_12 = -m_12 / det;
|
||||
m_21 = -m_21 / det;
|
||||
m_22 = m_11 / det;
|
||||
m_11 = e11;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns true if the elements of the transformation matrix are equal
|
||||
bool wxAffineMatrix2D::IsEqual(const wxAffineMatrix2DBase& t) const
|
||||
{
|
||||
wxMatrix2D mat;
|
||||
wxPoint2DDouble tr;
|
||||
t.Get(&mat, &tr);
|
||||
|
||||
return m_11 == mat.m_11 && m_12 == mat.m_12 &&
|
||||
m_21 == mat.m_21 && m_22 == mat.m_22 &&
|
||||
m_tx == tr.m_x && m_ty == tr.m_y;
|
||||
}
|
||||
|
||||
//
|
||||
// transformations
|
||||
//
|
||||
|
||||
// add the translation to this matrix
|
||||
// | 1 0 0 | | m_11 m_12 0 |
|
||||
// | 0 1 0 | x | m_21 m_22 0 |
|
||||
// | dx dy 1 | | m_tx m_ty 1 |
|
||||
void wxAffineMatrix2D::Translate(wxDouble dx, wxDouble dy)
|
||||
{
|
||||
m_tx += m_11 * dx + m_21 * dy;
|
||||
m_ty += m_12 * dx + m_22 * dy;
|
||||
}
|
||||
|
||||
// add the scale to this matrix
|
||||
// | xScale 0 0 | | m_11 m_12 0 |
|
||||
// | 0 yScale 0 | x | m_21 m_22 0 |
|
||||
// | 0 0 1 | | m_tx m_ty 1 |
|
||||
void wxAffineMatrix2D::Scale(wxDouble xScale, wxDouble yScale)
|
||||
{
|
||||
m_11 *= xScale;
|
||||
m_12 *= xScale;
|
||||
m_21 *= yScale;
|
||||
m_22 *= yScale;
|
||||
}
|
||||
|
||||
// add the rotation to this matrix (clockwise, radians)
|
||||
// | cos sin 0 | | m_11 m_12 0 |
|
||||
// | -sin cos 0 | x | m_21 m_22 0 |
|
||||
// | 0 0 1 | | m_tx m_ty 1 |
|
||||
void wxAffineMatrix2D::Rotate(wxDouble cRadians)
|
||||
{
|
||||
wxDouble c = cos(cRadians);
|
||||
wxDouble s = sin(cRadians);
|
||||
|
||||
wxDouble e11 = c*m_11 + s*m_21;
|
||||
wxDouble e12 = c*m_12 + s*m_22;
|
||||
m_21 = c*m_21 - s*m_11;
|
||||
m_22 = c*m_22 - s*m_12;
|
||||
m_11 = e11;
|
||||
m_12 = e12;
|
||||
}
|
||||
|
||||
//
|
||||
// apply the transforms
|
||||
//
|
||||
|
||||
// applies that matrix to the point
|
||||
// | m_11 m_12 0 |
|
||||
// | src.m_x src._my 1 | x | m_21 m_22 0 |
|
||||
// | m_tx m_ty 1 |
|
||||
wxPoint2DDouble
|
||||
wxAffineMatrix2D::DoTransformPoint(const wxPoint2DDouble& src) const
|
||||
{
|
||||
if ( IsIdentity() )
|
||||
return src;
|
||||
|
||||
return wxPoint2DDouble(src.m_x * m_11 + src.m_y * m_21 + m_tx,
|
||||
src.m_x * m_12 + src.m_y * m_22 + m_ty);
|
||||
}
|
||||
|
||||
// applies the matrix except for translations
|
||||
// | m_11 m_12 0 |
|
||||
// | src.m_x src._my 0 | x | m_21 m_22 0 |
|
||||
// | m_tx m_ty 1 |
|
||||
wxPoint2DDouble
|
||||
wxAffineMatrix2D::DoTransformDistance(const wxPoint2DDouble& src) const
|
||||
{
|
||||
if ( IsIdentity() )
|
||||
return src;
|
||||
|
||||
return wxPoint2DDouble(src.m_x * m_11 + src.m_y * m_21,
|
||||
src.m_x * m_12 + src.m_y * m_22);
|
||||
}
|
||||
|
||||
bool wxAffineMatrix2D::IsIdentity() const
|
||||
{
|
||||
return m_11 == 1 && m_12 == 0 &&
|
||||
m_21 == 0 && m_22 == 1 &&
|
||||
m_tx == 0 && m_ty == 0;
|
||||
}
|
||||
|
||||
#endif // wxUSE_GEOMETRY
|
||||
@@ -0,0 +1,542 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/any.cpp
|
||||
// Purpose: wxAny class, container for any type
|
||||
// Author: Jaakko Salli
|
||||
// Modified by:
|
||||
// Created: 07/05/2009
|
||||
// Copyright: (c) wxWidgets team
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx/wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/any.h"
|
||||
|
||||
#if wxUSE_ANY
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/math.h"
|
||||
#include "wx/crt.h"
|
||||
#endif
|
||||
|
||||
#include "wx/vector.h"
|
||||
#include "wx/module.h"
|
||||
#include "wx/hashmap.h"
|
||||
#include "wx/hashset.h"
|
||||
#include "wx/scopedptr.h"
|
||||
|
||||
using namespace wxPrivate;
|
||||
|
||||
#if wxUSE_VARIANT
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// wxAnyValueTypeGlobals
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
WX_DECLARE_HASH_MAP(wxAnyValueType*,
|
||||
wxVariantDataFactory,
|
||||
wxPointerHash,
|
||||
wxPointerEqual,
|
||||
wxAnyTypeToVariantDataFactoryMap);
|
||||
|
||||
//
|
||||
// Helper class to manage global variables related to type conversion
|
||||
// between wxAny and wxVariant.
|
||||
//
|
||||
class wxAnyValueTypeGlobals
|
||||
{
|
||||
public:
|
||||
wxAnyValueTypeGlobals()
|
||||
{
|
||||
}
|
||||
~wxAnyValueTypeGlobals()
|
||||
{
|
||||
m_anyToVariant.clear();
|
||||
}
|
||||
|
||||
void PreRegisterAnyToVariant(wxAnyToVariantRegistration* reg)
|
||||
{
|
||||
m_anyToVariantRegs.push_back(reg);
|
||||
}
|
||||
|
||||
// Find wxVariantData factory function for given value type,
|
||||
// (or compatible, if possible)
|
||||
wxVariantDataFactory FindVariantDataFactory(const wxAnyValueType* type_)
|
||||
{
|
||||
// Ideally we'd have the hash map of type 'const wxAnyValueType*',
|
||||
// but WX_DECLARE_HASH_MAP() has some trouble with it.
|
||||
wxAnyValueType* type = const_cast<wxAnyValueType*>(type_);
|
||||
|
||||
wxAnyTypeToVariantDataFactoryMap& anyToVariant = m_anyToVariant;
|
||||
wxAnyTypeToVariantDataFactoryMap::const_iterator it;
|
||||
it = anyToVariant.find(type);
|
||||
if ( it != anyToVariant.end() )
|
||||
return it->second;
|
||||
|
||||
// Not found, handle pre-registrations
|
||||
size_t i = m_anyToVariantRegs.size();
|
||||
while ( i > 0 )
|
||||
{
|
||||
i--;
|
||||
wxAnyToVariantRegistration* reg = m_anyToVariantRegs[i];
|
||||
wxAnyValueType* assocType = reg->GetAssociatedType();
|
||||
if ( assocType )
|
||||
{
|
||||
// Both variant data and wxAnyValueType have been
|
||||
// now been properly initialized, so remove the
|
||||
// pre-registration entry and move data to anyToVarian
|
||||
// map.
|
||||
anyToVariant[assocType] = reg->GetFactory();
|
||||
m_anyToVariantRegs.erase( m_anyToVariantRegs.begin() + i );
|
||||
}
|
||||
}
|
||||
|
||||
// Then try again
|
||||
it = anyToVariant.find(type);
|
||||
if ( it != anyToVariant.end() )
|
||||
return it->second;
|
||||
|
||||
// Finally, attempt to find a compatible type
|
||||
for ( it = anyToVariant.begin(); it != anyToVariant.end(); ++it )
|
||||
{
|
||||
if ( type->IsSameType(it->first) )
|
||||
{
|
||||
wxVariantDataFactory f = it->second;
|
||||
anyToVariant[type] = f;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
wxAnyTypeToVariantDataFactoryMap m_anyToVariant;
|
||||
wxVector<wxAnyToVariantRegistration*> m_anyToVariantRegs;
|
||||
};
|
||||
|
||||
static wxScopedPtr<wxAnyValueTypeGlobals>& GetAnyValueTypeGlobals()
|
||||
{
|
||||
static wxScopedPtr<wxAnyValueTypeGlobals> s_wxAnyValueTypeGlobals;
|
||||
if ( !s_wxAnyValueTypeGlobals )
|
||||
{
|
||||
// Notice that it is _not_ sufficient to just initialize the static
|
||||
// object like this because it can be used after it was reset by
|
||||
// wxAnyValueTypeGlobalsManager if the library is shut down and then
|
||||
// initialized again.
|
||||
s_wxAnyValueTypeGlobals.reset(new wxAnyValueTypeGlobals());
|
||||
}
|
||||
|
||||
return s_wxAnyValueTypeGlobals;
|
||||
}
|
||||
|
||||
|
||||
WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplVariantData)
|
||||
|
||||
void wxPreRegisterAnyToVariant(wxAnyToVariantRegistration* reg)
|
||||
{
|
||||
GetAnyValueTypeGlobals()->PreRegisterAnyToVariant(reg);
|
||||
}
|
||||
|
||||
bool wxConvertAnyToVariant(const wxAny& any, wxVariant* variant)
|
||||
{
|
||||
if ( any.IsNull() )
|
||||
{
|
||||
variant->MakeNull();
|
||||
return true;
|
||||
}
|
||||
|
||||
// (signed) integer is a special case, because there is only one type
|
||||
// in wxAny, and two ("long" and "longlong") in wxVariant. For better
|
||||
// backwards compatibility, convert all values that fit in "long",
|
||||
// and others to "longlong".
|
||||
if ( wxANY_CHECK_TYPE(any, signed int) )
|
||||
{
|
||||
#if defined(wxLongLong_t) && wxUSE_LONGLONG
|
||||
wxLongLong_t ll = 0;
|
||||
if ( any.GetAs(&ll) )
|
||||
{
|
||||
// NB: Do not use LONG_MAX here. Explicitly using 32-bit
|
||||
// integer constraint yields more consistent behaviour across
|
||||
// builds.
|
||||
if ( ll > wxINT32_MAX || ll < wxINT32_MIN )
|
||||
*variant = wxLongLong(ll);
|
||||
else
|
||||
*variant = (long) wxLongLong(ll).GetLo();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
long l;
|
||||
if ( any.GetAs(&l) )
|
||||
*variant = l;
|
||||
else
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find matching factory function
|
||||
wxVariantDataFactory f =
|
||||
GetAnyValueTypeGlobals()->FindVariantDataFactory(any.GetType());
|
||||
|
||||
wxVariantData* data = NULL;
|
||||
|
||||
if ( f )
|
||||
{
|
||||
data = f(any);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if wxAny wrapped wxVariantData*
|
||||
if ( !any.GetAs(&data) )
|
||||
{
|
||||
// Ok, one last chance: while unlikely, it is possible that the
|
||||
// wxAny actually contains wxVariant.
|
||||
if ( wxANY_CHECK_TYPE(any, wxVariant) )
|
||||
*variant = any.As<wxVariant>();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wrapper's GetValue() does not increase reference
|
||||
// count, se have to do it before the data gets passed
|
||||
// to a new variant.
|
||||
data->IncRef();
|
||||
}
|
||||
|
||||
variant->SetData(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// This class is to make sure that wxAnyValueType instances
|
||||
// etc. get freed correctly. We must use a separate wxAnyValueTypeGlobals
|
||||
// because wxModule itself is instantiated too late.
|
||||
//
|
||||
class wxAnyValueTypeGlobalsManager : public wxModule
|
||||
{
|
||||
wxDECLARE_DYNAMIC_CLASS(wxAnyValueTypeGlobalsManager);
|
||||
public:
|
||||
wxAnyValueTypeGlobalsManager() : wxModule() { }
|
||||
virtual ~wxAnyValueTypeGlobalsManager() { }
|
||||
|
||||
virtual bool OnInit() wxOVERRIDE
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual void OnExit() wxOVERRIDE
|
||||
{
|
||||
GetAnyValueTypeGlobals().reset();
|
||||
}
|
||||
private:
|
||||
};
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxAnyValueTypeGlobalsManager, wxModule);
|
||||
|
||||
#endif // wxUSE_VARIANT
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Dynamic conversion member functions
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// Define integer minimum and maximum as helpers
|
||||
#ifdef wxLongLong_t
|
||||
#define UseIntMin (wxINT64_MIN)
|
||||
#define UseIntMax (wxINT64_MAX)
|
||||
#define UseUintMax (wxUINT64_MAX)
|
||||
#else
|
||||
#define UseIntMin (LONG_MIN)
|
||||
#define UseIntMax (LONG_MAX)
|
||||
#define UseUintMax (ULONG_MAX)
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
const double UseIntMinF = static_cast<double>(UseIntMin);
|
||||
const double UseIntMaxF = static_cast<double>(UseIntMax);
|
||||
const double UseUintMaxF = static_cast<double>(UseUintMax);
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
bool wxAnyValueTypeImplInt::ConvertValue(const wxAnyValueBuffer& src,
|
||||
wxAnyValueType* dstType,
|
||||
wxAnyValueBuffer& dst) const
|
||||
{
|
||||
wxAnyBaseIntType value = GetValue(src);
|
||||
if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) )
|
||||
{
|
||||
#if defined(wxLongLong_t) && wxUSE_LONGLONG
|
||||
wxLongLong ll(value);
|
||||
wxString s = ll.ToString();
|
||||
#else
|
||||
wxString s = wxString::Format(wxS("%ld"), (long)value);
|
||||
#endif
|
||||
wxAnyValueTypeImpl<wxString>::SetValue(s, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseUintType) )
|
||||
{
|
||||
if ( value < 0 )
|
||||
return false;
|
||||
wxAnyBaseUintType ul = (wxAnyBaseUintType) value;
|
||||
wxAnyValueTypeImplUint::SetValue(ul, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, double) )
|
||||
{
|
||||
double value2 = static_cast<double>(value);
|
||||
wxAnyValueTypeImplDouble::SetValue(value2, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, bool) )
|
||||
{
|
||||
bool value2 = value ? true : false;
|
||||
wxAnyValueTypeImpl<bool>::SetValue(value2, dst);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxAnyValueTypeImplUint::ConvertValue(const wxAnyValueBuffer& src,
|
||||
wxAnyValueType* dstType,
|
||||
wxAnyValueBuffer& dst) const
|
||||
{
|
||||
wxAnyBaseUintType value = GetValue(src);
|
||||
if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) )
|
||||
{
|
||||
#if defined(wxLongLong_t) && wxUSE_LONGLONG
|
||||
wxULongLong ull(value);
|
||||
wxString s = ull.ToString();
|
||||
#else
|
||||
wxString s = wxString::Format(wxS("%lu"), (long)value);
|
||||
#endif
|
||||
wxAnyValueTypeImpl<wxString>::SetValue(s, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) )
|
||||
{
|
||||
if ( value > UseIntMax )
|
||||
return false;
|
||||
wxAnyBaseIntType l = (wxAnyBaseIntType) value;
|
||||
wxAnyValueTypeImplInt::SetValue(l, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, double) )
|
||||
{
|
||||
double value2 = static_cast<double>(value);
|
||||
wxAnyValueTypeImplDouble::SetValue(value2, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, bool) )
|
||||
{
|
||||
bool value2 = value ? true : false;
|
||||
wxAnyValueTypeImpl<bool>::SetValue(value2, dst);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert wxString to destination wxAny value type
|
||||
bool wxAnyConvertString(const wxString& value,
|
||||
wxAnyValueType* dstType,
|
||||
wxAnyValueBuffer& dst)
|
||||
{
|
||||
if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) )
|
||||
{
|
||||
wxAnyValueTypeImpl<wxString>::SetValue(value, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) )
|
||||
{
|
||||
wxAnyBaseIntType value2;
|
||||
#ifdef wxLongLong_t
|
||||
if ( !value.ToLongLong(&value2) )
|
||||
#else
|
||||
if ( !value.ToLong(&value2) )
|
||||
#endif
|
||||
return false;
|
||||
wxAnyValueTypeImplInt::SetValue(value2, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseUintType) )
|
||||
{
|
||||
wxAnyBaseUintType value2;
|
||||
#ifdef wxLongLong_t
|
||||
if ( !value.ToULongLong(&value2) )
|
||||
#else
|
||||
if ( !value.ToULong(&value2) )
|
||||
#endif
|
||||
return false;
|
||||
wxAnyValueTypeImplUint::SetValue(value2, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, double) )
|
||||
{
|
||||
double value2;
|
||||
if ( !value.ToCDouble(&value2) )
|
||||
return false;
|
||||
wxAnyValueTypeImplDouble::SetValue(value2, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, bool) )
|
||||
{
|
||||
bool value2;
|
||||
wxString s(value);
|
||||
s.MakeLower();
|
||||
if ( s == wxS("true") ||
|
||||
s == wxS("yes") ||
|
||||
s == wxS('1') )
|
||||
value2 = true;
|
||||
else if ( s == wxS("false") ||
|
||||
s == wxS("no") ||
|
||||
s == wxS('0') )
|
||||
value2 = false;
|
||||
else
|
||||
return false;
|
||||
|
||||
wxAnyValueTypeImpl<bool>::SetValue(value2, dst);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxAnyValueTypeImpl<bool>::ConvertValue(const wxAnyValueBuffer& src,
|
||||
wxAnyValueType* dstType,
|
||||
wxAnyValueBuffer& dst) const
|
||||
{
|
||||
bool value = GetValue(src);
|
||||
if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) )
|
||||
{
|
||||
wxAnyBaseIntType value2 = static_cast<wxAnyBaseIntType>(value);
|
||||
wxAnyValueTypeImplInt::SetValue(value2, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseUintType) )
|
||||
{
|
||||
wxAnyBaseIntType value2 = static_cast<wxAnyBaseUintType>(value);
|
||||
wxAnyValueTypeImplUint::SetValue(value2, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) )
|
||||
{
|
||||
wxString s;
|
||||
if ( value )
|
||||
s = wxS("true");
|
||||
else
|
||||
s = wxS("false");
|
||||
wxAnyValueTypeImpl<wxString>::SetValue(s, dst);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxAnyValueTypeImplDouble::ConvertValue(const wxAnyValueBuffer& src,
|
||||
wxAnyValueType* dstType,
|
||||
wxAnyValueBuffer& dst) const
|
||||
{
|
||||
double value = GetValue(src);
|
||||
if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) )
|
||||
{
|
||||
if ( value < UseIntMinF || value > UseIntMaxF )
|
||||
return false;
|
||||
wxAnyBaseUintType ul = static_cast<wxAnyBaseUintType>(value);
|
||||
wxAnyValueTypeImplUint::SetValue(ul, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseUintType) )
|
||||
{
|
||||
if ( value < 0.0 || value > UseUintMaxF )
|
||||
return false;
|
||||
wxAnyBaseUintType ul = static_cast<wxAnyBaseUintType>(value);
|
||||
wxAnyValueTypeImplUint::SetValue(ul, dst);
|
||||
}
|
||||
else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) )
|
||||
{
|
||||
wxString s = wxString::FromCDouble(value, 14);
|
||||
wxAnyValueTypeImpl<wxString>::SetValue(s, dst);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplInt)
|
||||
WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplUint)
|
||||
WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<bool>)
|
||||
WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplDouble)
|
||||
|
||||
WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplwxString)
|
||||
WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplConstCharPtr)
|
||||
WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplConstWchar_tPtr)
|
||||
|
||||
#if wxUSE_DATETIME
|
||||
WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxDateTime>)
|
||||
#endif // wxUSE_DATETIME
|
||||
|
||||
//WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxObject*>)
|
||||
//WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxArrayString>)
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// wxAnyNullValueType implementation
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
class wxAnyNullValue
|
||||
{
|
||||
protected:
|
||||
// this field is unused, but can't be private to avoid Clang's
|
||||
// "Private field 'm_dummy' is not used" warning
|
||||
void* m_dummy;
|
||||
};
|
||||
|
||||
template <>
|
||||
class wxAnyValueTypeImpl<wxAnyNullValue> : public wxAnyValueType
|
||||
{
|
||||
WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxAnyNullValue>)
|
||||
public:
|
||||
// Dummy implementations
|
||||
virtual void DeleteValue(wxAnyValueBuffer& buf) const wxOVERRIDE
|
||||
{
|
||||
wxUnusedVar(buf);
|
||||
}
|
||||
|
||||
virtual void CopyBuffer(const wxAnyValueBuffer& src,
|
||||
wxAnyValueBuffer& dst) const wxOVERRIDE
|
||||
{
|
||||
wxUnusedVar(src);
|
||||
wxUnusedVar(dst);
|
||||
}
|
||||
|
||||
virtual bool ConvertValue(const wxAnyValueBuffer& src,
|
||||
wxAnyValueType* dstType,
|
||||
wxAnyValueBuffer& dst) const wxOVERRIDE
|
||||
{
|
||||
wxUnusedVar(src);
|
||||
wxUnusedVar(dstType);
|
||||
wxUnusedVar(dst);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if wxUSE_EXTENDED_RTTI
|
||||
virtual const wxTypeInfo* GetTypeInfo() const
|
||||
{
|
||||
wxFAIL_MSG("Null Type Info not available");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxAnyNullValue>)
|
||||
|
||||
wxAnyValueType* wxAnyNullValueType =
|
||||
wxAnyValueTypeImpl<wxAnyNullValue>::GetInstance();
|
||||
|
||||
#include "wx/listimpl.cpp"
|
||||
WX_DEFINE_LIST(wxAnyList)
|
||||
|
||||
#endif // wxUSE_ANY
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/arcall.cpp
|
||||
// Purpose: wxArchive link all archive streams
|
||||
// Author: Mike Wetherell
|
||||
// Copyright: (c) 2006 Mike Wetherell
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_ARCHIVE_STREAMS
|
||||
|
||||
#if wxUSE_ZIPSTREAM
|
||||
#include "wx/zipstrm.h"
|
||||
#endif
|
||||
#if wxUSE_TARSTREAM
|
||||
#include "wx/tarstrm.h"
|
||||
#endif
|
||||
|
||||
// Reference archive classes to ensure they are linked into a statically
|
||||
// linked program that uses Find or GetFirst to look for an archive handler.
|
||||
// It is in its own file so that the user can override this behaviour by
|
||||
// providing their own implementation.
|
||||
|
||||
void wxUseArchiveClasses()
|
||||
{
|
||||
#if wxUSE_ZIPSTREAM
|
||||
wxZipClassFactory();
|
||||
#endif
|
||||
#if wxUSE_TARSTREAM
|
||||
wxTarClassFactory();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // wxUSE_ARCHIVE_STREAMS
|
||||
@@ -0,0 +1,39 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/arcfind.cpp
|
||||
// Purpose: Streams for archive formats
|
||||
// Author: Mike Wetherell
|
||||
// Copyright: (c) Mike Wetherell
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_ARCHIVE_STREAMS
|
||||
|
||||
#include "wx/archive.h"
|
||||
|
||||
// These functions are in a separate file so that statically linked apps
|
||||
// that do not call them to search for archive handlers will only link in
|
||||
// the archive classes they use.
|
||||
|
||||
const wxArchiveClassFactory *
|
||||
wxArchiveClassFactory::Find(const wxString& protocol, wxStreamProtocolType type)
|
||||
{
|
||||
for (const wxArchiveClassFactory *f = GetFirst(); f; f = f->GetNext())
|
||||
if (f->CanHandle(protocol, type))
|
||||
return f;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// static
|
||||
const wxArchiveClassFactory *wxArchiveClassFactory::GetFirst()
|
||||
{
|
||||
if (!sm_first)
|
||||
wxUseArchiveClasses();
|
||||
return sm_first;
|
||||
}
|
||||
|
||||
#endif // wxUSE_ARCHIVE_STREAMS
|
||||
@@ -0,0 +1,94 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/archive.cpp
|
||||
// Purpose: Streams for archive formats
|
||||
// Author: Mike Wetherell
|
||||
// Copyright: (c) Mike Wetherell
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS
|
||||
|
||||
#include "wx/archive.h"
|
||||
|
||||
wxIMPLEMENT_ABSTRACT_CLASS(wxArchiveEntry, wxObject);
|
||||
wxIMPLEMENT_ABSTRACT_CLASS(wxArchiveClassFactory, wxFilterClassFactoryBase);
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// wxArchiveInputStream
|
||||
|
||||
wxArchiveInputStream::wxArchiveInputStream(wxInputStream& stream,
|
||||
wxMBConv& conv)
|
||||
: wxFilterInputStream(stream),
|
||||
m_conv(conv)
|
||||
{
|
||||
}
|
||||
|
||||
wxArchiveInputStream::wxArchiveInputStream(wxInputStream *stream,
|
||||
wxMBConv& conv)
|
||||
: wxFilterInputStream(stream),
|
||||
m_conv(conv)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// wxArchiveOutputStream
|
||||
|
||||
wxArchiveOutputStream::wxArchiveOutputStream(wxOutputStream& stream,
|
||||
wxMBConv& conv)
|
||||
: wxFilterOutputStream(stream),
|
||||
m_conv(conv)
|
||||
{
|
||||
}
|
||||
|
||||
wxArchiveOutputStream::wxArchiveOutputStream(wxOutputStream *stream,
|
||||
wxMBConv& conv)
|
||||
: wxFilterOutputStream(stream),
|
||||
m_conv(conv)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// wxArchiveEntry
|
||||
|
||||
void wxArchiveEntry::SetNotifier(wxArchiveNotifier& notifier)
|
||||
{
|
||||
UnsetNotifier();
|
||||
m_notifier = ¬ifier;
|
||||
m_notifier->OnEntryUpdated(*this);
|
||||
}
|
||||
|
||||
wxArchiveEntry& wxArchiveEntry::operator=(const wxArchiveEntry& WXUNUSED(e))
|
||||
{
|
||||
m_notifier = NULL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// wxArchiveClassFactory
|
||||
|
||||
wxArchiveClassFactory *wxArchiveClassFactory::sm_first = NULL;
|
||||
|
||||
void wxArchiveClassFactory::Remove()
|
||||
{
|
||||
if (m_next != this)
|
||||
{
|
||||
wxArchiveClassFactory **pp = &sm_first;
|
||||
|
||||
while (*pp != this)
|
||||
pp = &(*pp)->m_next;
|
||||
|
||||
*pp = m_next;
|
||||
|
||||
m_next = this;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS
|
||||
@@ -0,0 +1,926 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/arrstr.cpp
|
||||
// Purpose: wxArrayString class
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 29/01/98
|
||||
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ===========================================================================
|
||||
// headers, declarations, constants
|
||||
// ===========================================================================
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/arrstr.h"
|
||||
#include "wx/scopedarray.h"
|
||||
#include "wx/wxcrt.h"
|
||||
|
||||
#include "wx/beforestd.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include "wx/afterstd.h"
|
||||
|
||||
#if defined( __WINDOWS__ )
|
||||
#include <shlwapi.h>
|
||||
|
||||
// In some distributions of MinGW32, this function is exported in the library,
|
||||
// but not declared in shlwapi.h. Therefore we declare it here.
|
||||
#if defined( __MINGW32_TOOLCHAIN__ )
|
||||
extern "C" __declspec(dllimport) int WINAPI StrCmpLogicalW(LPCWSTR psz1, LPCWSTR psz2);
|
||||
#endif
|
||||
|
||||
// For MSVC we can also link the library containing StrCmpLogicalW()
|
||||
// directly from here, for the other compilers this needs to be done at
|
||||
// makefiles level.
|
||||
#ifdef __VISUALC__
|
||||
#pragma comment(lib, "shlwapi")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// ArrayString
|
||||
// ============================================================================
|
||||
|
||||
wxArrayString::wxArrayString(size_t sz, const char** a)
|
||||
{
|
||||
#if !wxUSE_STD_CONTAINERS
|
||||
Init(false);
|
||||
#endif
|
||||
assign(a, a + sz);
|
||||
}
|
||||
|
||||
wxArrayString::wxArrayString(size_t sz, const wchar_t** a)
|
||||
{
|
||||
#if !wxUSE_STD_CONTAINERS
|
||||
Init(false);
|
||||
#endif
|
||||
assign(a, a + sz);
|
||||
}
|
||||
|
||||
wxArrayString::wxArrayString(size_t sz, const wxString* a)
|
||||
{
|
||||
#if !wxUSE_STD_CONTAINERS
|
||||
Init(false);
|
||||
#endif
|
||||
assign(a, a + sz);
|
||||
}
|
||||
|
||||
#if wxUSE_STD_CONTAINERS
|
||||
|
||||
#include "wx/arrstr.h"
|
||||
|
||||
#if __cplusplus >= 201103L || wxCHECK_VISUALC_VERSION(14)
|
||||
|
||||
int wxArrayString::Index(const wxString& str, bool bCase, bool WXUNUSED(bFromEnd)) const
|
||||
{
|
||||
int n = 0;
|
||||
for ( const auto& s: *this )
|
||||
{
|
||||
if ( s.IsSameAs(str, bCase) )
|
||||
return n;
|
||||
|
||||
++n;
|
||||
}
|
||||
|
||||
return wxNOT_FOUND;
|
||||
}
|
||||
|
||||
#else // C++98 version
|
||||
|
||||
#include "wx/beforestd.h"
|
||||
#include <functional>
|
||||
#include "wx/afterstd.h"
|
||||
|
||||
// some compilers (Sun CC being the only known example) distinguish between
|
||||
// extern "C" functions and the functions with C++ linkage and ptr_fun and
|
||||
// wxStringCompareLess can't take wxStrcmp/wxStricmp directly as arguments in
|
||||
// this case, we need the wrappers below to make this work
|
||||
struct wxStringCmp
|
||||
{
|
||||
typedef wxString first_argument_type;
|
||||
typedef wxString second_argument_type;
|
||||
typedef int result_type;
|
||||
|
||||
int operator()(const wxString& s1, const wxString& s2) const
|
||||
{
|
||||
return s1.compare(s2);
|
||||
}
|
||||
};
|
||||
|
||||
struct wxStringCmpNoCase
|
||||
{
|
||||
typedef wxString first_argument_type;
|
||||
typedef wxString second_argument_type;
|
||||
typedef int result_type;
|
||||
|
||||
int operator()(const wxString& s1, const wxString& s2) const
|
||||
{
|
||||
return s1.CmpNoCase(s2);
|
||||
}
|
||||
};
|
||||
|
||||
int wxArrayString::Index(const wxString& str, bool bCase, bool WXUNUSED(bFromEnd)) const
|
||||
{
|
||||
wxArrayString::const_iterator it;
|
||||
|
||||
if (bCase)
|
||||
{
|
||||
it = std::find_if(begin(), end(),
|
||||
std::not1(
|
||||
std::bind2nd(
|
||||
wxStringCmp(), str)));
|
||||
}
|
||||
else // !bCase
|
||||
{
|
||||
it = std::find_if(begin(), end(),
|
||||
std::not1(
|
||||
std::bind2nd(
|
||||
wxStringCmpNoCase(), str)));
|
||||
}
|
||||
|
||||
return it == end() ? wxNOT_FOUND : it - begin();
|
||||
}
|
||||
|
||||
template<class F>
|
||||
class wxStringCompareLess
|
||||
{
|
||||
public:
|
||||
wxStringCompareLess(F f) : m_f(f) { }
|
||||
bool operator()(const wxString& s1, const wxString& s2)
|
||||
{ return m_f(s1, s2) < 0; }
|
||||
private:
|
||||
F m_f;
|
||||
};
|
||||
|
||||
template<class F>
|
||||
wxStringCompareLess<F> wxStringCompare(F f)
|
||||
{
|
||||
return wxStringCompareLess<F>(f);
|
||||
}
|
||||
|
||||
#endif // C++11/C++98
|
||||
|
||||
void wxArrayString::Sort(CompareFunction function)
|
||||
{
|
||||
std::sort(begin(), end(),
|
||||
#if __cplusplus >= 201103L || wxCHECK_VISUALC_VERSION(14)
|
||||
[function](const wxString& s1, const wxString& s2)
|
||||
{
|
||||
return function(s1, s2) < 0;
|
||||
}
|
||||
#else // C++98 version
|
||||
wxStringCompare(function)
|
||||
#endif // C++11/C++98
|
||||
);
|
||||
}
|
||||
|
||||
void wxArrayString::Sort(bool reverseOrder)
|
||||
{
|
||||
if (reverseOrder)
|
||||
{
|
||||
std::sort(begin(), end(), std::greater<wxString>());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::sort(begin(), end());
|
||||
}
|
||||
}
|
||||
|
||||
int wxSortedArrayString::Index(const wxString& str,
|
||||
bool WXUNUSED_UNLESS_DEBUG(bCase),
|
||||
bool WXUNUSED_UNLESS_DEBUG(bFromEnd)) const
|
||||
{
|
||||
wxASSERT_MSG( bCase && !bFromEnd,
|
||||
"search parameters ignored for sorted array" );
|
||||
|
||||
SCMPFUNC function = GetCompareFunction();
|
||||
wxSortedArrayString::const_iterator
|
||||
it = std::lower_bound(begin(), end(), str,
|
||||
#if __cplusplus >= 201103L || wxCHECK_VISUALC_VERSION(14)
|
||||
[function](const wxString& s1, const wxString& s2)
|
||||
{
|
||||
return function(s1, s2) < 0;
|
||||
}
|
||||
#else // C++98 version
|
||||
wxStringCompare(function)
|
||||
#endif // C++11/C++98
|
||||
);
|
||||
|
||||
if ( it == end() || str.Cmp(*it) != 0 )
|
||||
return wxNOT_FOUND;
|
||||
|
||||
return it - begin();
|
||||
}
|
||||
|
||||
#else // !wxUSE_STD_CONTAINERS
|
||||
|
||||
#ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
|
||||
#define ARRAY_DEFAULT_INITIAL_SIZE (16)
|
||||
#endif
|
||||
|
||||
// ctor
|
||||
void wxArrayString::Init(bool autoSort)
|
||||
{
|
||||
m_nSize =
|
||||
m_nCount = 0;
|
||||
m_pItems = NULL;
|
||||
m_compareFunction = NULL;
|
||||
m_autoSort = autoSort;
|
||||
}
|
||||
|
||||
// copy ctor
|
||||
wxArrayString::wxArrayString(const wxArrayString& src)
|
||||
{
|
||||
Init(src.m_autoSort);
|
||||
|
||||
*this = src;
|
||||
}
|
||||
|
||||
// assignment operator
|
||||
wxArrayString& wxArrayString::operator=(const wxArrayString& src)
|
||||
{
|
||||
if ( m_nSize > 0 )
|
||||
{
|
||||
// Do this test here to avoid unnecessary overhead when assigning to an
|
||||
// empty array, in that case there is no harm in self-assignment.
|
||||
if ( &src == this )
|
||||
return *this;
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
Copy(src);
|
||||
|
||||
m_autoSort = src.m_autoSort;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void wxArrayString::Copy(const wxArrayString& src)
|
||||
{
|
||||
if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
|
||||
Alloc(src.m_nCount);
|
||||
|
||||
for ( size_t n = 0; n < src.m_nCount; n++ )
|
||||
Add(src[n]);
|
||||
}
|
||||
|
||||
// grow the array
|
||||
wxString *wxArrayString::Grow(size_t nIncrement)
|
||||
{
|
||||
if ( (m_nSize - m_nCount) >= nIncrement )
|
||||
{
|
||||
// We already have enough space.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would
|
||||
// be never resized!
|
||||
#if ARRAY_DEFAULT_INITIAL_SIZE == 0
|
||||
#error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!"
|
||||
#endif
|
||||
|
||||
if ( m_nSize == 0 ) {
|
||||
// was empty, alloc some memory
|
||||
m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
|
||||
if (m_nSize < nIncrement)
|
||||
m_nSize = nIncrement;
|
||||
m_pItems = new wxString[m_nSize];
|
||||
|
||||
// Nothing to free, we hadn't had any memory before.
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
// otherwise when it's called for the first time, nIncrement would be 0
|
||||
// and the array would never be expanded
|
||||
size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
|
||||
? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize;
|
||||
if ( nIncrement < ndefIncrement )
|
||||
nIncrement = ndefIncrement;
|
||||
m_nSize += nIncrement;
|
||||
wxString *pNew = new wxString[m_nSize];
|
||||
|
||||
// copy data to new location
|
||||
for ( size_t j = 0; j < m_nCount; j++ )
|
||||
pNew[j] = m_pItems[j];
|
||||
|
||||
wxString* const pItemsOld = m_pItems;
|
||||
|
||||
m_pItems = pNew;
|
||||
|
||||
return pItemsOld;
|
||||
}
|
||||
}
|
||||
|
||||
// deletes all the strings from the list
|
||||
void wxArrayString::Empty()
|
||||
{
|
||||
m_nCount = 0;
|
||||
}
|
||||
|
||||
// as Empty, but also frees memory
|
||||
void wxArrayString::Clear()
|
||||
{
|
||||
m_nSize =
|
||||
m_nCount = 0;
|
||||
|
||||
wxDELETEA(m_pItems);
|
||||
}
|
||||
|
||||
// dtor
|
||||
wxArrayString::~wxArrayString()
|
||||
{
|
||||
delete [] m_pItems;
|
||||
}
|
||||
|
||||
void wxArrayString::reserve(size_t nSize)
|
||||
{
|
||||
Alloc(nSize);
|
||||
}
|
||||
|
||||
// pre-allocates memory (frees the previous data!)
|
||||
void wxArrayString::Alloc(size_t nSize)
|
||||
{
|
||||
// only if old buffer was not big enough
|
||||
if ( nSize > m_nSize ) {
|
||||
wxString *pNew = new wxString[nSize];
|
||||
if ( !pNew )
|
||||
return;
|
||||
|
||||
for ( size_t j = 0; j < m_nCount; j++ )
|
||||
pNew[j] = m_pItems[j];
|
||||
delete [] m_pItems;
|
||||
|
||||
m_pItems = pNew;
|
||||
m_nSize = nSize;
|
||||
}
|
||||
}
|
||||
|
||||
// minimizes the memory usage by freeing unused memory
|
||||
void wxArrayString::Shrink()
|
||||
{
|
||||
// only do it if we have some memory to free
|
||||
if( m_nCount < m_nSize ) {
|
||||
// allocates exactly as much memory as we need
|
||||
wxString *pNew = new wxString[m_nCount];
|
||||
|
||||
// copy data to new location
|
||||
for ( size_t j = 0; j < m_nCount; j++ )
|
||||
pNew[j] = m_pItems[j];
|
||||
delete [] m_pItems;
|
||||
m_pItems = pNew;
|
||||
m_nSize = m_nCount;
|
||||
}
|
||||
}
|
||||
|
||||
// Binary search in the sorted array
|
||||
size_t wxArrayString::BinarySearch(const wxString& str, bool lowerBound) const
|
||||
{
|
||||
size_t
|
||||
lo = 0,
|
||||
hi = m_nCount;
|
||||
while (lo < hi) {
|
||||
size_t i;
|
||||
i = (lo + hi) / 2;
|
||||
|
||||
int res;
|
||||
res = m_compareFunction ? m_compareFunction(str, m_pItems[i]) : str.Cmp(m_pItems[i]);
|
||||
if (res < 0)
|
||||
hi = i;
|
||||
else if (res > 0)
|
||||
lo = i + 1;
|
||||
else
|
||||
return i;
|
||||
}
|
||||
wxASSERT_MSG(lo == hi, wxT("binary search broken"));
|
||||
return lowerBound ? lo : wxNOT_FOUND;
|
||||
}
|
||||
|
||||
// searches the array for an item (forward or backwards)
|
||||
int wxArrayString::Index(const wxString& str, bool bCase, bool bFromEnd) const
|
||||
{
|
||||
if ( m_autoSort ) {
|
||||
// use binary search in the sorted array
|
||||
wxASSERT_MSG( bCase && !bFromEnd,
|
||||
wxT("search parameters ignored for auto sorted array") );
|
||||
return BinarySearch(str, false /* not lower bound */);
|
||||
}
|
||||
else {
|
||||
// use linear search in unsorted array
|
||||
if ( bFromEnd ) {
|
||||
if ( m_nCount > 0 ) {
|
||||
size_t ui = m_nCount;
|
||||
do {
|
||||
if ( m_pItems[--ui].IsSameAs(str, bCase) )
|
||||
return ui;
|
||||
}
|
||||
while ( ui != 0 );
|
||||
}
|
||||
}
|
||||
else {
|
||||
for( size_t ui = 0; ui < m_nCount; ui++ ) {
|
||||
if( m_pItems[ui].IsSameAs(str, bCase) )
|
||||
return ui;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wxNOT_FOUND;
|
||||
}
|
||||
|
||||
// add item at the end
|
||||
size_t wxArrayString::Add(const wxString& str, size_t nInsert)
|
||||
{
|
||||
if ( m_autoSort ) {
|
||||
// insert the string at the correct position to keep the array sorted
|
||||
size_t nIndex = BinarySearch(str, true /* return lower bound */);
|
||||
Insert(str, nIndex, nInsert);
|
||||
return nIndex;
|
||||
}
|
||||
else {
|
||||
// Now that we must postpone freeing the old memory until we don't need it
|
||||
// any more, i.e. don't reference "str" which could be a reference to one
|
||||
// of our own strings.
|
||||
wxScopedArray<wxString> oldStrings(Grow(nInsert));
|
||||
|
||||
for (size_t i = 0; i < nInsert; i++)
|
||||
{
|
||||
// just append
|
||||
m_pItems[m_nCount + i] = str;
|
||||
}
|
||||
size_t ret = m_nCount;
|
||||
m_nCount += nInsert;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// add item at the given position
|
||||
void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert)
|
||||
{
|
||||
wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") );
|
||||
wxCHECK_RET( m_nCount <= m_nCount + nInsert,
|
||||
wxT("array size overflow in wxArrayString::Insert") );
|
||||
|
||||
wxScopedArray<wxString> oldStrings(Grow(nInsert));
|
||||
|
||||
for (int j = m_nCount - nIndex - 1; j >= 0; j--)
|
||||
m_pItems[nIndex + nInsert + j] = m_pItems[nIndex + j];
|
||||
|
||||
for (size_t i = 0; i < nInsert; i++)
|
||||
{
|
||||
m_pItems[nIndex + i] = str;
|
||||
}
|
||||
m_nCount += nInsert;
|
||||
}
|
||||
|
||||
// range insert (STL 23.2.4.3)
|
||||
void
|
||||
wxArrayString::insert(iterator it, const_iterator first, const_iterator last)
|
||||
{
|
||||
const int idx = it - begin();
|
||||
|
||||
// grow it once
|
||||
wxScopedArray<wxString> oldStrings(Grow(last - first));
|
||||
|
||||
// reset "it" since it can change inside Grow()
|
||||
it = begin() + idx;
|
||||
|
||||
while ( first != last )
|
||||
{
|
||||
it = insert(it, *first);
|
||||
|
||||
// insert returns an iterator to the last element inserted but we need
|
||||
// insert the next after this one, that is before the next one
|
||||
++it;
|
||||
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
void wxArrayString::resize(size_type n, value_type v)
|
||||
{
|
||||
if ( n < m_nCount )
|
||||
m_nCount = n;
|
||||
else if ( n > m_nCount )
|
||||
Add(v, n - m_nCount);
|
||||
}
|
||||
|
||||
// expand the array
|
||||
void wxArrayString::SetCount(size_t count)
|
||||
{
|
||||
Alloc(count);
|
||||
|
||||
wxString s;
|
||||
while ( m_nCount < count )
|
||||
m_pItems[m_nCount++] = s;
|
||||
}
|
||||
|
||||
// removes item from array (by index)
|
||||
void wxArrayString::RemoveAt(size_t nIndex, size_t nRemove)
|
||||
{
|
||||
wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") );
|
||||
wxCHECK_RET( nIndex + nRemove <= m_nCount,
|
||||
wxT("removing too many elements in wxArrayString::Remove") );
|
||||
|
||||
for ( size_t j = 0; j < m_nCount - nIndex -nRemove; j++)
|
||||
m_pItems[nIndex + j] = m_pItems[nIndex + nRemove + j];
|
||||
|
||||
m_nCount -= nRemove;
|
||||
}
|
||||
|
||||
// removes item from array (by value)
|
||||
void wxArrayString::Remove(const wxString& sz)
|
||||
{
|
||||
int iIndex = Index(sz);
|
||||
|
||||
wxCHECK_RET( iIndex != wxNOT_FOUND,
|
||||
wxT("removing inexistent element in wxArrayString::Remove") );
|
||||
|
||||
RemoveAt(iIndex);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// sorting
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// we need an adaptor as our predicates use qsort() convention and so return
|
||||
// negative, null or positive value depending on whether the first item is less
|
||||
// than, equal to or greater than the other one while we need a real boolean
|
||||
// predicate now that we use std::sort()
|
||||
struct wxSortPredicateAdaptor
|
||||
{
|
||||
wxSortPredicateAdaptor(wxArrayString::CompareFunction compareFunction)
|
||||
: m_compareFunction(compareFunction)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()(const wxString& first, const wxString& second) const
|
||||
{
|
||||
return (*m_compareFunction)(first, second) < 0;
|
||||
}
|
||||
|
||||
wxArrayString::CompareFunction m_compareFunction;
|
||||
};
|
||||
|
||||
void wxArrayString::Sort(CompareFunction compareFunction)
|
||||
{
|
||||
wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") );
|
||||
|
||||
std::sort(m_pItems, m_pItems + m_nCount,
|
||||
wxSortPredicateAdaptor(compareFunction));
|
||||
}
|
||||
|
||||
struct wxSortPredicateAdaptor2
|
||||
{
|
||||
wxSortPredicateAdaptor2(wxArrayString::CompareFunction2 compareFunction)
|
||||
: m_compareFunction(compareFunction)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()(const wxString& first, const wxString& second) const
|
||||
{
|
||||
return (*m_compareFunction)(const_cast<wxString *>(&first),
|
||||
const_cast<wxString *>(&second)) < 0;
|
||||
}
|
||||
|
||||
wxArrayString::CompareFunction2 m_compareFunction;
|
||||
};
|
||||
|
||||
void wxArrayString::Sort(CompareFunction2 compareFunction)
|
||||
{
|
||||
std::sort(m_pItems, m_pItems + m_nCount,
|
||||
wxSortPredicateAdaptor2(compareFunction));
|
||||
}
|
||||
|
||||
void wxArrayString::Sort(bool reverseOrder)
|
||||
{
|
||||
if ( reverseOrder )
|
||||
std::sort(m_pItems, m_pItems + m_nCount, std::greater<wxString>());
|
||||
else // normal sort
|
||||
std::sort(m_pItems, m_pItems + m_nCount);
|
||||
}
|
||||
|
||||
bool wxArrayString::operator==(const wxArrayString& a) const
|
||||
{
|
||||
if ( m_nCount != a.m_nCount )
|
||||
return false;
|
||||
|
||||
for ( size_t n = 0; n < m_nCount; n++ )
|
||||
{
|
||||
if ( Item(n) != a[n] )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // !wxUSE_STD_CONTAINERS
|
||||
|
||||
// ===========================================================================
|
||||
// wxJoin and wxSplit
|
||||
// ===========================================================================
|
||||
|
||||
#include "wx/tokenzr.h"
|
||||
|
||||
wxString wxJoin(const wxArrayString& arr, const wxChar sep, const wxChar escape)
|
||||
{
|
||||
wxString str;
|
||||
|
||||
size_t count = arr.size();
|
||||
if ( count == 0 )
|
||||
return str;
|
||||
|
||||
// pre-allocate memory using the estimation of the average length of the
|
||||
// strings in the given array: this is very imprecise, of course, but
|
||||
// better than nothing
|
||||
str.reserve(count*(arr[0].length() + arr[count-1].length()) / 2);
|
||||
|
||||
if ( escape == wxT('\0') )
|
||||
{
|
||||
// escaping is disabled:
|
||||
for ( size_t i = 0; i < count; i++ )
|
||||
{
|
||||
if ( i )
|
||||
str += sep;
|
||||
str += arr[i];
|
||||
}
|
||||
}
|
||||
else // use escape character
|
||||
{
|
||||
for ( size_t n = 0; n < count; n++ )
|
||||
{
|
||||
if ( n )
|
||||
{
|
||||
// We don't escape the escape characters in the middle of the
|
||||
// string because this is not needed, strictly speaking, but we
|
||||
// must do it if they occur at the end because otherwise we
|
||||
// wouldn't split the string back correctly as the separator
|
||||
// would appear to be escaped.
|
||||
if ( !str.empty() && *str.rbegin() == escape )
|
||||
str += escape;
|
||||
|
||||
str += sep;
|
||||
}
|
||||
|
||||
for ( wxString::const_iterator i = arr[n].begin(),
|
||||
end = arr[n].end();
|
||||
i != end;
|
||||
++i )
|
||||
{
|
||||
const wxChar ch = *i;
|
||||
if ( ch == sep )
|
||||
str += escape; // escape this separator
|
||||
str += ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str.Shrink(); // release extra memory if we allocated too much
|
||||
return str;
|
||||
}
|
||||
|
||||
wxArrayString wxSplit(const wxString& str, const wxChar sep, const wxChar escape)
|
||||
{
|
||||
if ( escape == wxT('\0') )
|
||||
{
|
||||
// simple case: we don't need to honour the escape character
|
||||
return wxStringTokenize(str, sep, wxTOKEN_RET_EMPTY_ALL);
|
||||
}
|
||||
|
||||
wxArrayString ret;
|
||||
wxString curr;
|
||||
|
||||
for ( wxString::const_iterator i = str.begin(),
|
||||
end = str.end();
|
||||
i != end;
|
||||
++i )
|
||||
{
|
||||
const wxChar ch = *i;
|
||||
|
||||
// Order of tests matters here in the uncommon, but possible, case when
|
||||
// the separator is the same as the escape character: it has to be
|
||||
// recognized as a separator in this case (escaping doesn't work at all
|
||||
// in this case).
|
||||
if ( ch == sep )
|
||||
{
|
||||
ret.push_back(curr);
|
||||
curr.clear();
|
||||
}
|
||||
else if ( ch == escape )
|
||||
{
|
||||
++i;
|
||||
if ( i == end )
|
||||
{
|
||||
// Escape at the end of the string is not handled specially.
|
||||
curr += ch;
|
||||
break;
|
||||
}
|
||||
|
||||
// Separator or the escape character itself may be escaped,
|
||||
// cancelling their special meaning, but escape character followed
|
||||
// by anything else is not handled specially.
|
||||
if ( *i != sep && *i != escape )
|
||||
curr += ch;
|
||||
|
||||
curr += *i;
|
||||
}
|
||||
else // normal character
|
||||
{
|
||||
curr += ch;
|
||||
}
|
||||
}
|
||||
|
||||
// add the last token, which we always have unless the string is empty
|
||||
if ( !str.empty() )
|
||||
ret.Add(curr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
namespace // helpers needed by wxCmpNaturalGeneric()
|
||||
{
|
||||
// Used for comparison of string parts
|
||||
struct wxStringFragment
|
||||
{
|
||||
// Fragment types are generally sorted like this:
|
||||
// Empty < SpaceOrPunct < Digit < LetterOrSymbol
|
||||
// Fragments of the same type are compared as follows:
|
||||
// SpaceOrPunct - collated, Digit - as numbers using value
|
||||
// LetterOrSymbol - lower-cased and then collated
|
||||
enum Type
|
||||
{
|
||||
Empty,
|
||||
SpaceOrPunct, // whitespace or punctuation
|
||||
Digit, // a sequence of decimal digits
|
||||
LetterOrSymbol // letters and symbols, i.e., anything not covered by the above types
|
||||
};
|
||||
|
||||
wxStringFragment() : type(Empty), value(0) {}
|
||||
|
||||
Type type;
|
||||
wxString text;
|
||||
wxUint64 value; // used only for Digit type
|
||||
};
|
||||
|
||||
|
||||
wxStringFragment GetFragment(wxString& text)
|
||||
{
|
||||
if ( text.empty() )
|
||||
return wxStringFragment();
|
||||
|
||||
// the maximum length of a sequence of digits that
|
||||
// can fit into wxUint64 when converted to a number
|
||||
static const ptrdiff_t maxDigitSequenceLength = 19;
|
||||
|
||||
wxStringFragment fragment;
|
||||
wxString::const_iterator it;
|
||||
|
||||
for ( it = text.cbegin(); it != text.cend(); ++it )
|
||||
{
|
||||
const wxUniChar& ch = *it;
|
||||
wxStringFragment::Type chType = wxStringFragment::Empty;
|
||||
|
||||
if ( wxIsspace(ch) || wxIspunct(ch) )
|
||||
chType = wxStringFragment::SpaceOrPunct;
|
||||
else if ( wxIsdigit(ch) )
|
||||
chType = wxStringFragment::Digit;
|
||||
else
|
||||
chType = wxStringFragment::LetterOrSymbol;
|
||||
|
||||
// check if evaluating the first character
|
||||
if ( fragment.type == wxStringFragment::Empty )
|
||||
{
|
||||
fragment.type = chType;
|
||||
continue;
|
||||
}
|
||||
|
||||
// stop processing when the current character has a different
|
||||
// string fragment type than the previously processed characters had
|
||||
// or a sequence of digits is too long
|
||||
if ( fragment.type != chType
|
||||
|| (fragment.type == wxStringFragment::Digit
|
||||
&& it - text.cbegin() > maxDigitSequenceLength) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fragment.text.assign(text.cbegin(), it);
|
||||
if ( fragment.type == wxStringFragment::Digit )
|
||||
fragment.text.ToULongLong(&fragment.value);
|
||||
|
||||
text.erase(0, it - text.cbegin());
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
int CompareFragmentNatural(const wxStringFragment& lhs, const wxStringFragment& rhs)
|
||||
{
|
||||
switch ( lhs.type )
|
||||
{
|
||||
case wxStringFragment::Empty:
|
||||
switch ( rhs.type )
|
||||
{
|
||||
case wxStringFragment::Empty:
|
||||
return 0;
|
||||
case wxStringFragment::SpaceOrPunct:
|
||||
case wxStringFragment::Digit:
|
||||
case wxStringFragment::LetterOrSymbol:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case wxStringFragment::SpaceOrPunct:
|
||||
switch ( rhs.type )
|
||||
{
|
||||
case wxStringFragment::Empty:
|
||||
return 1;
|
||||
case wxStringFragment::SpaceOrPunct:
|
||||
return wxStrcoll_String(lhs.text, rhs.text);
|
||||
case wxStringFragment::Digit:
|
||||
case wxStringFragment::LetterOrSymbol:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case wxStringFragment::Digit:
|
||||
switch ( rhs.type )
|
||||
{
|
||||
case wxStringFragment::Empty:
|
||||
case wxStringFragment::SpaceOrPunct:
|
||||
return 1;
|
||||
case wxStringFragment::Digit:
|
||||
if ( lhs.value > rhs.value )
|
||||
return 1;
|
||||
else if ( lhs.value < rhs.value )
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
case wxStringFragment::LetterOrSymbol:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case wxStringFragment::LetterOrSymbol:
|
||||
switch ( rhs.type )
|
||||
{
|
||||
case wxStringFragment::Empty:
|
||||
case wxStringFragment::SpaceOrPunct:
|
||||
case wxStringFragment::Digit:
|
||||
return 1;
|
||||
case wxStringFragment::LetterOrSymbol:
|
||||
return wxStrcoll_String(lhs.text.Lower(), rhs.text.Lower());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// all possible cases should be covered by the switch above
|
||||
// but return also from here to prevent the compiler warning
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxCmpNaturalGeneric
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
int wxCMPFUNC_CONV wxCmpNaturalGeneric(const wxString& s1, const wxString& s2)
|
||||
{
|
||||
wxString lhs(s1);
|
||||
wxString rhs(s2);
|
||||
|
||||
int comparison = 0;
|
||||
|
||||
while ( (comparison == 0) && (!lhs.empty() || !rhs.empty()) )
|
||||
{
|
||||
const wxStringFragment fragmentLHS = GetFragment(lhs);
|
||||
const wxStringFragment fragmentRHS = GetFragment(rhs);
|
||||
|
||||
comparison = CompareFragmentNatural(fragmentLHS, fragmentRHS);
|
||||
}
|
||||
|
||||
return comparison;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxCmpNatural
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// If a native version of Natural sort is available, then use that, otherwise
|
||||
// use the generic version.
|
||||
int wxCMPFUNC_CONV wxCmpNatural(const wxString& s1, const wxString& s2)
|
||||
{
|
||||
#if defined( __WINDOWS__ )
|
||||
return StrCmpLogicalW(s1.wc_str(), s2.wc_str());
|
||||
#else
|
||||
return wxCmpNaturalGeneric(s1, s2);
|
||||
#endif // #if defined( __WINDOWS__ )
|
||||
}
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/base64.cpp
|
||||
// Purpose: implementation of BASE64 encoding/decoding functions
|
||||
// Author: Charles Reimers, Vadim Zeitlin
|
||||
// Created: 2007-06-18
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_BASE64
|
||||
|
||||
#include "wx/base64.h"
|
||||
|
||||
size_t
|
||||
wxBase64Encode(char *dst, size_t dstLen, const void *src_, size_t srcLen)
|
||||
{
|
||||
wxCHECK_MSG( src_, wxCONV_FAILED, wxT("NULL input buffer") );
|
||||
|
||||
const unsigned char *src = static_cast<const unsigned char *>(src_);
|
||||
|
||||
static const char b64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
|
||||
size_t encLen = 0;
|
||||
|
||||
// encode blocks of 3 bytes into 4 base64 characters
|
||||
for ( ; srcLen >= 3; srcLen -= 3, src += 3 )
|
||||
{
|
||||
encLen += 4;
|
||||
if ( dst )
|
||||
{
|
||||
if ( encLen > dstLen )
|
||||
return wxCONV_FAILED;
|
||||
|
||||
*dst++ = b64[src[0] >> 2];
|
||||
*dst++ = b64[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)];
|
||||
*dst++ = b64[((src[1] & 0x0f) << 2) | ((src[2] & 0xc0) >> 6)];
|
||||
*dst++ = b64[src[2] & 0x3f];
|
||||
}
|
||||
}
|
||||
|
||||
// finish with the remaining characters
|
||||
if ( srcLen )
|
||||
{
|
||||
encLen += 4;
|
||||
if ( dst )
|
||||
{
|
||||
if ( encLen > dstLen )
|
||||
return wxCONV_FAILED;
|
||||
|
||||
// we have definitely one and maybe two bytes remaining
|
||||
unsigned char next = srcLen == 2 ? src[1] : 0;
|
||||
*dst++ = b64[src[0] >> 2];
|
||||
*dst++ = b64[((src[0] & 0x03) << 4) | ((next & 0xf0) >> 4)];
|
||||
*dst++ = srcLen == 2 ? b64[((next & 0x0f) << 2)] : '=';
|
||||
*dst = '=';
|
||||
}
|
||||
}
|
||||
|
||||
return encLen;
|
||||
}
|
||||
|
||||
size_t
|
||||
wxBase64Decode(void *dst_, size_t dstLen,
|
||||
const char *src, size_t srcLen,
|
||||
wxBase64DecodeMode mode,
|
||||
size_t *posErr)
|
||||
{
|
||||
wxCHECK_MSG( src, wxCONV_FAILED, wxT("NULL input buffer") );
|
||||
|
||||
unsigned char *dst = static_cast<unsigned char *>(dst_);
|
||||
|
||||
size_t decLen = 0;
|
||||
|
||||
if ( srcLen == wxNO_LEN )
|
||||
srcLen = strlen(src);
|
||||
|
||||
// this table contains the values, in base 64, of all valid characters and
|
||||
// special values WSP or INV for white space and invalid characters
|
||||
// respectively as well as a special PAD value for '='
|
||||
enum
|
||||
{
|
||||
WSP = 200,
|
||||
INV,
|
||||
PAD
|
||||
};
|
||||
|
||||
static const unsigned char decode[256] =
|
||||
{
|
||||
WSP,INV,INV,INV,INV,INV,INV,INV,INV,WSP,WSP,INV,WSP,WSP,INV,INV,
|
||||
INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
|
||||
WSP,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,076,INV,INV,INV,077,
|
||||
064,065,066,067,070,071,072,073,074,075,INV,INV,INV,PAD,INV,INV,
|
||||
INV,000,001,002,003,004,005,006,007,010,011,012,013,014,015,016,
|
||||
017,020,021,022,023,024,025,026,027,030,031,INV,INV,INV,INV,INV,
|
||||
INV,032,033,034,035,036,037,040,041,042,043,044,045,046,047,050,
|
||||
051,052,053,054,055,056,057,060,061,062,063,INV,INV,INV,INV,INV,
|
||||
INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
|
||||
INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
|
||||
INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
|
||||
INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
|
||||
INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
|
||||
INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
|
||||
INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
|
||||
INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,INV,
|
||||
};
|
||||
|
||||
// we decode input by groups of 4 characters but things are complicated by
|
||||
// the fact that there can be whitespace and other junk in it too so keep
|
||||
// record of where exactly we're inside the current quartet in this var
|
||||
int n = 0;
|
||||
unsigned char in[4]; // current quartet
|
||||
bool end = false; // set when we find padding
|
||||
size_t padLen = 0; // length lost to padding
|
||||
const char *p;
|
||||
for ( p = src; srcLen; p++, srcLen-- )
|
||||
{
|
||||
const unsigned char c = decode[static_cast<unsigned char>(*p)];
|
||||
switch ( c )
|
||||
{
|
||||
case WSP:
|
||||
if ( mode == wxBase64DecodeMode_SkipWS )
|
||||
continue;
|
||||
wxFALLTHROUGH;
|
||||
|
||||
case INV:
|
||||
if ( mode == wxBase64DecodeMode_Relaxed )
|
||||
continue;
|
||||
|
||||
// force the loop to stop and an error to be returned
|
||||
n = -1;
|
||||
srcLen = 1;
|
||||
break;
|
||||
|
||||
case PAD:
|
||||
// set the flag telling us that we're past the end now
|
||||
end = true;
|
||||
|
||||
// there can be either a single '=' at the end of a quartet or
|
||||
// "==" in positions 2 and 3
|
||||
if ( n == 3 )
|
||||
{
|
||||
padLen = 1;
|
||||
in[n++] = '\0';
|
||||
}
|
||||
else if ( (n == 2) && (--srcLen && *++p == '=') )
|
||||
{
|
||||
padLen = 2;
|
||||
in[n++] = '\0';
|
||||
in[n++] = '\0';
|
||||
}
|
||||
else // invalid padding
|
||||
{
|
||||
// force the loop terminate with an error
|
||||
n = -1;
|
||||
srcLen = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( end )
|
||||
{
|
||||
// nothing is allowed after the end so provoke error return
|
||||
n = -1;
|
||||
srcLen = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
in[n++] = c;
|
||||
}
|
||||
|
||||
if ( n == 4 )
|
||||
{
|
||||
// got entire block, decode
|
||||
decLen += 3 - padLen;
|
||||
if ( dst )
|
||||
{
|
||||
if ( decLen > dstLen )
|
||||
return wxCONV_FAILED;
|
||||
|
||||
// undo the bit shifting done during encoding
|
||||
*dst++ = in[0] << 2 | in[1] >> 4;
|
||||
|
||||
// be careful to not overwrite the output buffer with NUL pad
|
||||
// bytes
|
||||
if ( padLen != 2 )
|
||||
{
|
||||
*dst++ = in[1] << 4 | in[2] >> 2;
|
||||
if ( !padLen )
|
||||
*dst++ = in[2] << 6 | in[3];
|
||||
}
|
||||
}
|
||||
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( n )
|
||||
{
|
||||
if ( posErr )
|
||||
{
|
||||
// notice that the error was on a previous position as we did one
|
||||
// extra "p++" in the loop line after it
|
||||
*posErr = p - src - 1;
|
||||
}
|
||||
|
||||
return wxCONV_FAILED;
|
||||
}
|
||||
|
||||
return decLen;
|
||||
}
|
||||
|
||||
wxMemoryBuffer wxBase64Decode(const char *src,
|
||||
size_t srcLen,
|
||||
wxBase64DecodeMode mode,
|
||||
size_t *posErr)
|
||||
{
|
||||
wxMemoryBuffer buf;
|
||||
wxCHECK_MSG( src, buf, wxT("NULL input buffer") );
|
||||
|
||||
if ( srcLen == wxNO_LEN )
|
||||
srcLen = strlen(src);
|
||||
|
||||
size_t len = wxBase64DecodedSize(srcLen);
|
||||
len = wxBase64Decode(buf.GetWriteBuf(len), len, src, srcLen, mode, posErr);
|
||||
if ( len == wxCONV_FAILED )
|
||||
len = 0;
|
||||
|
||||
buf.SetDataLen(len);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif // wxUSE_BASE64
|
||||
@@ -0,0 +1,77 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/clntdata.cpp
|
||||
// Purpose: A mixin class for holding a wxClientData or void pointer
|
||||
// Author: Robin Dunn
|
||||
// Modified by:
|
||||
// Created: 9-Oct-2001
|
||||
// Copyright: (c) wxWidgets team
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/clntdata.h"
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
wxClientDataContainer::wxClientDataContainer()
|
||||
{
|
||||
// no client data (yet)
|
||||
m_clientData = NULL;
|
||||
m_clientDataType = wxClientData_None;
|
||||
}
|
||||
|
||||
wxClientDataContainer::~wxClientDataContainer()
|
||||
{
|
||||
// we only delete object data, not untyped
|
||||
if ( m_clientDataType == wxClientData_Object )
|
||||
delete m_clientObject;
|
||||
}
|
||||
|
||||
void wxClientDataContainer::DoSetClientObject( wxClientData *data )
|
||||
{
|
||||
wxASSERT_MSG( m_clientDataType != wxClientData_Void,
|
||||
wxT("can't have both object and void client data") );
|
||||
|
||||
delete m_clientObject;
|
||||
m_clientObject = data;
|
||||
m_clientDataType = wxClientData_Object;
|
||||
}
|
||||
|
||||
wxClientData *wxClientDataContainer::DoGetClientObject() const
|
||||
{
|
||||
// it's not an error to call GetClientObject() on a window which doesn't
|
||||
// have client data at all - NULL will be returned
|
||||
wxASSERT_MSG( m_clientDataType != wxClientData_Void,
|
||||
wxT("this window doesn't have object client data") );
|
||||
|
||||
return m_clientObject;
|
||||
}
|
||||
|
||||
void wxClientDataContainer::DoSetClientData( void *data )
|
||||
{
|
||||
wxASSERT_MSG( m_clientDataType != wxClientData_Object,
|
||||
wxT("can't have both object and void client data") );
|
||||
|
||||
m_clientData = data;
|
||||
m_clientDataType = wxClientData_Void;
|
||||
}
|
||||
|
||||
void *wxClientDataContainer::DoGetClientData() const
|
||||
{
|
||||
// it's not an error to call GetClientData() on a window which doesn't have
|
||||
// client data at all - NULL will be returned
|
||||
wxASSERT_MSG( m_clientDataType != wxClientData_Object,
|
||||
wxT("this window doesn't have void client data") );
|
||||
|
||||
return m_clientData;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,600 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/config.cpp
|
||||
// Purpose: implementation of wxConfigBase class
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 07.04.98
|
||||
// Copyright: (c) 1997 Karsten Ballueder Ballueder@usa.net
|
||||
// Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
#ifndef wxUSE_CONFIG_NATIVE
|
||||
#define wxUSE_CONFIG_NATIVE 1
|
||||
#endif
|
||||
|
||||
#include "wx/config.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/intl.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/app.h"
|
||||
#include "wx/utils.h"
|
||||
#include "wx/arrstr.h"
|
||||
#include "wx/math.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#if wxUSE_CONFIG && ((wxUSE_FILE && wxUSE_TEXTFILE) || wxUSE_CONFIG_NATIVE)
|
||||
|
||||
#include "wx/apptrait.h"
|
||||
#include "wx/file.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h> // for INT_MAX
|
||||
#include <float.h> // for FLT_MAX
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// global and class static variables
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxConfigBase *wxConfigBase::ms_pConfig = NULL;
|
||||
bool wxConfigBase::ms_bAutoCreate = true;
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxAppTraitsBase
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxConfigBase *wxAppTraitsBase::CreateConfig()
|
||||
{
|
||||
return new
|
||||
#if defined(__WINDOWS__) && wxUSE_CONFIG_NATIVE
|
||||
wxRegConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName());
|
||||
#else // either we're under Unix or wish to use files even under Windows
|
||||
wxFileConfig(wxTheApp->GetAppName());
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxConfigBase
|
||||
// ----------------------------------------------------------------------------
|
||||
wxIMPLEMENT_ABSTRACT_CLASS(wxConfigBase, wxObject);
|
||||
|
||||
// Not all args will always be used by derived classes, but including them all
|
||||
// in each class ensures compatibility.
|
||||
wxConfigBase::wxConfigBase(const wxString& appName,
|
||||
const wxString& vendorName,
|
||||
const wxString& WXUNUSED(localFilename),
|
||||
const wxString& WXUNUSED(globalFilename),
|
||||
long style)
|
||||
: m_appName(appName), m_vendorName(vendorName), m_style(style)
|
||||
{
|
||||
m_bExpandEnvVars = true;
|
||||
m_bRecordDefaults = false;
|
||||
}
|
||||
|
||||
wxConfigBase::~wxConfigBase()
|
||||
{
|
||||
// required here for Darwin
|
||||
}
|
||||
|
||||
wxConfigBase *wxConfigBase::Set(wxConfigBase *pConfig)
|
||||
{
|
||||
wxConfigBase *pOld = ms_pConfig;
|
||||
ms_pConfig = pConfig;
|
||||
return pOld;
|
||||
}
|
||||
|
||||
wxConfigBase *wxConfigBase::Create()
|
||||
{
|
||||
if ( ms_bAutoCreate && ms_pConfig == NULL ) {
|
||||
wxAppTraits * const traits = wxApp::GetTraitsIfExists();
|
||||
wxCHECK_MSG( traits, NULL, wxT("create wxApp before calling this") );
|
||||
|
||||
ms_pConfig = traits->CreateConfig();
|
||||
}
|
||||
|
||||
return ms_pConfig;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxConfigBase reading entries
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// implement both Read() overloads for the given type in terms of DoRead()
|
||||
#define IMPLEMENT_READ_FOR_TYPE(name, type, deftype, extra) \
|
||||
bool wxConfigBase::Read(const wxString& key, type *val) const \
|
||||
{ \
|
||||
wxCHECK_MSG( val, false, wxT("wxConfig::Read(): NULL parameter") ); \
|
||||
\
|
||||
if ( !DoRead##name(key, val) ) \
|
||||
return false; \
|
||||
\
|
||||
*val = (extra)(*val); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool wxConfigBase::Read(const wxString& key, \
|
||||
type *val, \
|
||||
deftype defVal) const \
|
||||
{ \
|
||||
wxCHECK_MSG( val, false, wxT("wxConfig::Read(): NULL parameter") ); \
|
||||
\
|
||||
bool read = DoRead##name(key, val); \
|
||||
if ( !read ) \
|
||||
{ \
|
||||
if ( IsRecordingDefaults() ) \
|
||||
{ \
|
||||
const_cast<wxConfigBase*>(this)->DoWrite##name(key, defVal);\
|
||||
} \
|
||||
\
|
||||
*val = defVal; \
|
||||
} \
|
||||
\
|
||||
*val = (extra)(*val); \
|
||||
\
|
||||
return read; \
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_READ_FOR_TYPE(String, wxString, const wxString&, ExpandEnvVars)
|
||||
IMPLEMENT_READ_FOR_TYPE(Long, long, long, long)
|
||||
#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
||||
IMPLEMENT_READ_FOR_TYPE(LongLong, wxLongLong_t, wxLongLong_t, wxLongLong_t)
|
||||
#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
||||
IMPLEMENT_READ_FOR_TYPE(Double, double, double, double)
|
||||
IMPLEMENT_READ_FOR_TYPE(Bool, bool, bool, bool)
|
||||
|
||||
#undef IMPLEMENT_READ_FOR_TYPE
|
||||
|
||||
// int is stored as long
|
||||
bool wxConfigBase::Read(const wxString& key, int *pi) const
|
||||
{
|
||||
long l = *pi;
|
||||
bool r = Read(key, &l);
|
||||
wxASSERT_MSG( l < INT_MAX, wxT("int overflow in wxConfig::Read") );
|
||||
*pi = (int)l;
|
||||
return r;
|
||||
}
|
||||
|
||||
bool wxConfigBase::Read(const wxString& key, int *pi, int defVal) const
|
||||
{
|
||||
long l = *pi;
|
||||
bool r = Read(key, &l, defVal);
|
||||
wxASSERT_MSG( l < INT_MAX, wxT("int overflow in wxConfig::Read") );
|
||||
*pi = (int)l;
|
||||
return r;
|
||||
}
|
||||
|
||||
// size_t is stored either as long or long long (Win64)
|
||||
#if SIZEOF_SIZE_T == SIZEOF_LONG
|
||||
typedef long SizeSameSizeAsSizeT;
|
||||
#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
|
||||
typedef wxLongLong_t SizeSameSizeAsSizeT;
|
||||
#else
|
||||
#error Unexpected sizeof(size_t)
|
||||
#endif
|
||||
|
||||
bool wxConfigBase::Read(const wxString& key, size_t* val) const
|
||||
{
|
||||
wxCHECK_MSG( val, false, wxT("wxConfig::Read(): NULL parameter") );
|
||||
|
||||
SizeSameSizeAsSizeT tmp;
|
||||
if ( !Read(key, &tmp) )
|
||||
return false;
|
||||
|
||||
*val = static_cast<size_t>(tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxConfigBase::Read(const wxString& key, size_t* val, size_t defVal) const
|
||||
{
|
||||
wxCHECK_MSG( val, false, wxT("wxConfig::Read(): NULL parameter") );
|
||||
|
||||
if ( !Read(key, val) )
|
||||
{
|
||||
*val = defVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read floats as doubles then just type cast it down.
|
||||
bool wxConfigBase::Read(const wxString& key, float* val) const
|
||||
{
|
||||
wxCHECK_MSG( val, false, wxT("wxConfig::Read(): NULL parameter") );
|
||||
|
||||
double temp;
|
||||
if ( !Read(key, &temp) )
|
||||
return false;
|
||||
|
||||
wxCHECK_MSG( fabs(temp) <= double(FLT_MAX), false,
|
||||
wxT("float overflow in wxConfig::Read") );
|
||||
wxCHECK_MSG( temp == 0.0 || fabs(temp) >= double(FLT_MIN), false,
|
||||
wxT("float underflow in wxConfig::Read") );
|
||||
|
||||
*val = static_cast<float>(temp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxConfigBase::Read(const wxString& key, float* val, float defVal) const
|
||||
{
|
||||
wxCHECK_MSG( val, false, wxT("wxConfig::Read(): NULL parameter") );
|
||||
|
||||
if ( Read(key, val) )
|
||||
return true;
|
||||
|
||||
*val = defVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
// the DoReadXXX() for the other types have implementation in the base class
|
||||
// but can be overridden in the derived ones
|
||||
bool wxConfigBase::DoReadBool(const wxString& key, bool* val) const
|
||||
{
|
||||
wxCHECK_MSG( val, false, wxT("wxConfig::Read(): NULL parameter") );
|
||||
|
||||
long l;
|
||||
if ( !DoReadLong(key, &l) )
|
||||
return false;
|
||||
|
||||
if ( l != 0 && l != 1 )
|
||||
{
|
||||
// Don't assert here as this could happen in the result of user editing
|
||||
// the file directly and this not indicate a bug in the program but
|
||||
// still complain that something is wrong.
|
||||
wxLogWarning(_("Invalid value %ld for a boolean key \"%s\" in "
|
||||
"config file."),
|
||||
l, key);
|
||||
}
|
||||
|
||||
*val = l != 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
||||
|
||||
bool wxConfigBase::DoReadLongLong(const wxString& key, wxLongLong_t *pll) const
|
||||
{
|
||||
wxString str;
|
||||
if ( !Read(key, &str) )
|
||||
return false;
|
||||
|
||||
str.Trim();
|
||||
|
||||
return str.ToLongLong(pll);
|
||||
}
|
||||
|
||||
#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
||||
|
||||
bool wxConfigBase::DoReadDouble(const wxString& key, double* val) const
|
||||
{
|
||||
wxString str;
|
||||
if ( Read(key, &str) )
|
||||
{
|
||||
if ( str.ToCDouble(val) )
|
||||
return true;
|
||||
|
||||
// Previous versions of wxFileConfig wrote the numbers out using the
|
||||
// current locale and not the C one as now, so attempt to parse the
|
||||
// string as a number in the current locale too, for compatibility.
|
||||
if ( str.ToDouble(val) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// string reading helper
|
||||
wxString wxConfigBase::ExpandEnvVars(const wxString& str) const
|
||||
{
|
||||
wxString tmp; // Required for BC++
|
||||
if (IsExpandingEnvVars())
|
||||
tmp = wxExpandEnvVars(str);
|
||||
else
|
||||
tmp = str;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxConfigBase writing
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
||||
|
||||
bool wxConfigBase::DoWriteLongLong(const wxString& key, wxLongLong_t llValue)
|
||||
{
|
||||
return Write(key, wxString::Format("%" wxLongLongFmtSpec "d", llValue));
|
||||
}
|
||||
|
||||
#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
||||
|
||||
bool wxConfigBase::DoWriteDouble(const wxString& key, double val)
|
||||
{
|
||||
// Notice that we always write out the numbers in C locale and not the
|
||||
// current one. This makes the config files portable between machines using
|
||||
// different locales.
|
||||
return DoWriteString(key, wxString::FromCDouble(val));
|
||||
}
|
||||
|
||||
bool wxConfigBase::DoWriteBool(const wxString& key, bool value)
|
||||
{
|
||||
return DoWriteLong(key, value ? 1l : 0l);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxConfigPathChanger
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxConfigPathChanger::wxConfigPathChanger(const wxConfigBase *pContainer,
|
||||
const wxString& strEntry)
|
||||
{
|
||||
m_bChanged = false;
|
||||
m_pContainer = const_cast<wxConfigBase *>(pContainer);
|
||||
|
||||
// the path is everything which precedes the last slash and the name is
|
||||
// everything after it -- and this works correctly if there is no slash too
|
||||
wxString strPath = strEntry.BeforeLast(wxCONFIG_PATH_SEPARATOR, &m_strName);
|
||||
|
||||
// except in the special case of "/keyname" when there is nothing before "/"
|
||||
if ( strPath.empty() &&
|
||||
((!strEntry.empty()) && strEntry[0] == wxCONFIG_PATH_SEPARATOR) )
|
||||
{
|
||||
strPath = wxCONFIG_PATH_SEPARATOR;
|
||||
}
|
||||
|
||||
if ( !strPath.empty() )
|
||||
{
|
||||
if ( m_pContainer->GetPath() != strPath )
|
||||
{
|
||||
// we do change the path so restore it later
|
||||
m_bChanged = true;
|
||||
|
||||
/* JACS: work around a memory bug that causes an assert
|
||||
when using wxRegConfig, related to reference-counting.
|
||||
Can be reproduced by removing .wc_str() below and
|
||||
adding the following code to the config sample OnInit under
|
||||
Windows:
|
||||
|
||||
pConfig->SetPath(wxT("MySettings"));
|
||||
pConfig->SetPath(wxT(".."));
|
||||
int value;
|
||||
pConfig->Read(wxT("MainWindowX"), & value);
|
||||
*/
|
||||
m_strOldPath = m_pContainer->GetPath().wc_str();
|
||||
if ( *m_strOldPath.c_str() != wxCONFIG_PATH_SEPARATOR )
|
||||
m_strOldPath += wxCONFIG_PATH_SEPARATOR;
|
||||
m_pContainer->SetPath(strPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxConfigPathChanger::UpdateIfDeleted()
|
||||
{
|
||||
// we don't have to do anything at all if we didn't change the path
|
||||
if ( !m_bChanged )
|
||||
return;
|
||||
|
||||
// find the deepest still existing parent path of the original path
|
||||
while ( !m_pContainer->HasGroup(m_strOldPath) )
|
||||
{
|
||||
m_strOldPath = m_strOldPath.BeforeLast(wxCONFIG_PATH_SEPARATOR);
|
||||
if ( m_strOldPath.empty() )
|
||||
m_strOldPath = wxCONFIG_PATH_SEPARATOR;
|
||||
}
|
||||
}
|
||||
|
||||
wxConfigPathChanger::~wxConfigPathChanger()
|
||||
{
|
||||
// only restore path if it was changed
|
||||
if ( m_bChanged ) {
|
||||
m_pContainer->SetPath(m_strOldPath);
|
||||
}
|
||||
}
|
||||
|
||||
// this is a wxConfig method but it's mainly used with wxConfigPathChanger
|
||||
/* static */
|
||||
wxString wxConfigBase::RemoveTrailingSeparator(const wxString& key)
|
||||
{
|
||||
wxString path(key);
|
||||
|
||||
// don't remove the only separator from a root group path!
|
||||
while ( path.length() > 1 )
|
||||
{
|
||||
if ( *path.rbegin() != wxCONFIG_PATH_SEPARATOR )
|
||||
break;
|
||||
|
||||
path.erase(path.end() - 1);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
#endif // wxUSE_CONFIG
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// static & global functions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// understands both Unix and Windows (but only under Windows) environment
|
||||
// variables expansion: i.e. $var, $(var) and ${var} are always understood
|
||||
// and in addition under Windows %var% is also.
|
||||
|
||||
// don't change the values the enum elements: they must be equal
|
||||
// to the matching [closing] delimiter.
|
||||
enum Bracket
|
||||
{
|
||||
Bracket_None,
|
||||
Bracket_Normal = ')',
|
||||
Bracket_Curly = '}',
|
||||
#ifdef __WINDOWS__
|
||||
Bracket_Windows = '%', // yeah, Windows people are a bit strange ;-)
|
||||
#endif
|
||||
Bracket_Max
|
||||
};
|
||||
|
||||
wxString wxExpandEnvVars(const wxString& str)
|
||||
{
|
||||
wxString strResult;
|
||||
strResult.Alloc(str.length());
|
||||
|
||||
size_t m;
|
||||
for ( size_t n = 0; n < str.length(); n++ ) {
|
||||
switch ( str[n].GetValue() ) {
|
||||
#ifdef __WINDOWS__
|
||||
case wxT('%'):
|
||||
#endif // __WINDOWS__
|
||||
case wxT('$'):
|
||||
{
|
||||
Bracket bracket;
|
||||
#ifdef __WINDOWS__
|
||||
if ( str[n] == wxT('%') )
|
||||
bracket = Bracket_Windows;
|
||||
else
|
||||
#endif // __WINDOWS__
|
||||
if ( n == str.length() - 1 ) {
|
||||
bracket = Bracket_None;
|
||||
}
|
||||
else {
|
||||
switch ( str[n + 1].GetValue() ) {
|
||||
case wxT('('):
|
||||
bracket = Bracket_Normal;
|
||||
n++; // skip the bracket
|
||||
break;
|
||||
|
||||
case wxT('{'):
|
||||
bracket = Bracket_Curly;
|
||||
n++; // skip the bracket
|
||||
break;
|
||||
|
||||
default:
|
||||
bracket = Bracket_None;
|
||||
}
|
||||
}
|
||||
|
||||
m = n + 1;
|
||||
|
||||
while ( m < str.length() && (wxIsalnum(str[m]) || str[m] == wxT('_')) )
|
||||
m++;
|
||||
|
||||
wxString strVarName(str.c_str() + n + 1, m - n - 1);
|
||||
|
||||
// NB: use wxGetEnv instead of wxGetenv as otherwise variables
|
||||
// set through wxSetEnv may not be read correctly!
|
||||
bool expanded = false;
|
||||
wxString tmp;
|
||||
if (wxGetEnv(strVarName, &tmp))
|
||||
{
|
||||
strResult += tmp;
|
||||
expanded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// variable doesn't exist => don't change anything
|
||||
#ifdef __WINDOWS__
|
||||
if ( bracket != Bracket_Windows )
|
||||
#endif
|
||||
if ( bracket != Bracket_None )
|
||||
strResult << str[n - 1];
|
||||
strResult << str[n] << strVarName;
|
||||
}
|
||||
|
||||
// check the closing bracket
|
||||
if ( bracket != Bracket_None ) {
|
||||
if ( m == str.length() || str[m] != (wxChar)bracket ) {
|
||||
// under MSW it's common to have '%' characters in the registry
|
||||
// and it's annoying to have warnings about them each time, so
|
||||
// ignroe them silently if they are not used for env vars
|
||||
//
|
||||
// under Unix, OTOH, this warning could be useful for the user to
|
||||
// understand why isn't the variable expanded as intended
|
||||
#ifndef __WINDOWS__
|
||||
wxLogWarning(_("Environment variables expansion failed: missing '%c' at position %u in '%s'."),
|
||||
(char)bracket, (unsigned int) (m + 1), str.c_str());
|
||||
#endif // __WINDOWS__
|
||||
}
|
||||
else {
|
||||
// skip closing bracket unless the variables wasn't expanded
|
||||
if ( !expanded )
|
||||
strResult << (wxChar)bracket;
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
n = m - 1; // skip variable name
|
||||
}
|
||||
break;
|
||||
|
||||
case wxT('\\'):
|
||||
// backslash can be used to suppress special meaning of % and $
|
||||
if ( n != str.length() - 1 &&
|
||||
(str[n + 1] == wxT('%') || str[n + 1] == wxT('$')) ) {
|
||||
strResult += str[++n];
|
||||
|
||||
break;
|
||||
}
|
||||
wxFALLTHROUGH;
|
||||
|
||||
default:
|
||||
strResult += str[n];
|
||||
}
|
||||
}
|
||||
|
||||
return strResult;
|
||||
}
|
||||
|
||||
// this function is used to properly interpret '..' in path
|
||||
void wxSplitPath(wxArrayString& aParts, const wxString& path)
|
||||
{
|
||||
aParts.clear();
|
||||
|
||||
wxString strCurrent;
|
||||
wxString::const_iterator pc = path.begin();
|
||||
for ( ;; ) {
|
||||
if ( pc == path.end() || *pc == wxCONFIG_PATH_SEPARATOR ) {
|
||||
if ( strCurrent == wxT(".") ) {
|
||||
// ignore
|
||||
}
|
||||
else if ( strCurrent == wxT("..") ) {
|
||||
// go up one level
|
||||
if ( aParts.size() == 0 )
|
||||
{
|
||||
wxLogWarning(_("'%s' has extra '..', ignored."), path);
|
||||
}
|
||||
else
|
||||
{
|
||||
aParts.erase(aParts.end() - 1);
|
||||
}
|
||||
|
||||
strCurrent.Empty();
|
||||
}
|
||||
else if ( !strCurrent.empty() ) {
|
||||
aParts.push_back(strCurrent);
|
||||
strCurrent.Empty();
|
||||
}
|
||||
//else:
|
||||
// could log an error here, but we prefer to ignore extra '/'
|
||||
|
||||
if ( pc == path.end() )
|
||||
break;
|
||||
}
|
||||
else
|
||||
strCurrent += *pc;
|
||||
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/convauto.cpp
|
||||
// Purpose: implementation of wxConvAuto
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2006-04-04
|
||||
// Copyright: (c) 2006 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/convauto.h"
|
||||
#include "wx/private/unicode.h"
|
||||
|
||||
// we use latin1 by default as it seems the least bad choice: the files we need
|
||||
// to detect input of don't always come from the user system (they are often
|
||||
// received from other machines) and so using wxFONTENCODING_SYSTEM doesn't
|
||||
// seem to be a good idea and there is no other reasonable alternative
|
||||
wxFontEncoding wxConvAuto::ms_defaultMBEncoding = wxFONTENCODING_ISO8859_1;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
const char BOM_UTF32BE[] = { '\x00', '\x00', '\xFE', '\xFF' };
|
||||
const char BOM_UTF32LE[] = { '\xFF', '\xFE', '\x00', '\x00' };
|
||||
const char BOM_UTF16BE[] = { '\xFE', '\xFF' };
|
||||
const char BOM_UTF16LE[] = { '\xFF', '\xFE' };
|
||||
const char BOM_UTF8[] = { '\xEF', '\xBB', '\xBF' };
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
/* static */
|
||||
void wxConvAuto::SetFallbackEncoding(wxFontEncoding enc)
|
||||
{
|
||||
wxASSERT_MSG( enc != wxFONTENCODING_DEFAULT,
|
||||
wxT("wxFONTENCODING_DEFAULT doesn't make sense here") );
|
||||
|
||||
ms_defaultMBEncoding = enc;
|
||||
}
|
||||
|
||||
/* static */
|
||||
const char* wxConvAuto::GetBOMChars(wxBOM bom, size_t* count)
|
||||
{
|
||||
wxCHECK_MSG( count , NULL, wxS("count pointer must be provided") );
|
||||
|
||||
switch ( bom )
|
||||
{
|
||||
case wxBOM_UTF32BE: *count = WXSIZEOF(BOM_UTF32BE); return BOM_UTF32BE;
|
||||
case wxBOM_UTF32LE: *count = WXSIZEOF(BOM_UTF32LE); return BOM_UTF32LE;
|
||||
case wxBOM_UTF16BE: *count = WXSIZEOF(BOM_UTF16BE); return BOM_UTF16BE;
|
||||
case wxBOM_UTF16LE: *count = WXSIZEOF(BOM_UTF16LE); return BOM_UTF16LE;
|
||||
case wxBOM_UTF8 : *count = WXSIZEOF(BOM_UTF8 ); return BOM_UTF8;
|
||||
case wxBOM_Unknown:
|
||||
case wxBOM_None:
|
||||
wxFAIL_MSG( wxS("Invalid BOM type") );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wxFAIL_MSG( wxS("Unknown BOM type") );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxBOM wxConvAuto::DetectBOM(const char *src, size_t srcLen)
|
||||
{
|
||||
// examine the buffer for BOM presence
|
||||
//
|
||||
// quoting from http://www.unicode.org/faq/utf_bom.html#BOM:
|
||||
//
|
||||
// Bytes Encoding Form
|
||||
//
|
||||
// 00 00 FE FF UTF-32, big-endian
|
||||
// FF FE 00 00 UTF-32, little-endian
|
||||
// FE FF UTF-16, big-endian
|
||||
// FF FE UTF-16, little-endian
|
||||
// EF BB BF UTF-8
|
||||
//
|
||||
// as some BOMs are prefixes of other ones we may need to read more bytes
|
||||
// to disambiguate them
|
||||
|
||||
switch ( srcLen )
|
||||
{
|
||||
case 0:
|
||||
return wxBOM_Unknown;
|
||||
|
||||
case 1:
|
||||
if ( src[0] == '\x00' || src[0] == '\xFF' ||
|
||||
src[0] == '\xFE' || src[0] == '\xEF')
|
||||
{
|
||||
// this could be a BOM but we don't know yet
|
||||
return wxBOM_Unknown;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
if ( src[0] == '\xEF' && src[1] == '\xBB' )
|
||||
{
|
||||
if ( srcLen == 3 )
|
||||
return src[2] == '\xBF' ? wxBOM_UTF8 : wxBOM_None;
|
||||
|
||||
return wxBOM_Unknown;
|
||||
}
|
||||
|
||||
if ( src[0] == '\xFE' && src[1] == '\xFF' )
|
||||
return wxBOM_UTF16BE;
|
||||
|
||||
if ( src[0] == '\xFF' && src[1] == '\xFE' )
|
||||
{
|
||||
// if the next byte is 0, it could be an UTF-32LE BOM but if it
|
||||
// isn't we can be sure it's UTF-16LE
|
||||
if ( srcLen == 3 && src[2] != '\x00' )
|
||||
return wxBOM_UTF16LE;
|
||||
|
||||
return wxBOM_Unknown;
|
||||
}
|
||||
|
||||
if ( src[0] == '\x00' && src[1] == '\x00' )
|
||||
{
|
||||
// this could only be UTF-32BE, check that the data we have so
|
||||
// far allows for it
|
||||
if ( srcLen == 3 && src[2] != '\xFE' )
|
||||
return wxBOM_None;
|
||||
|
||||
return wxBOM_Unknown;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// we have at least 4 characters so we may finally decide whether
|
||||
// we have a BOM or not
|
||||
if ( src[0] == '\xEF' && src[1] == '\xBB' && src[2] == '\xBF' )
|
||||
return wxBOM_UTF8;
|
||||
|
||||
if ( src[0] == '\x00' && src[1] == '\x00' &&
|
||||
src[2] == '\xFE' && src[3] == '\xFF' )
|
||||
return wxBOM_UTF32BE;
|
||||
|
||||
if ( src[0] == '\xFF' && src[1] == '\xFE' &&
|
||||
src[2] == '\x00' && src[3] == '\x00' )
|
||||
return wxBOM_UTF32LE;
|
||||
|
||||
if ( src[0] == '\xFE' && src[1] == '\xFF' )
|
||||
return wxBOM_UTF16BE;
|
||||
|
||||
if ( src[0] == '\xFF' && src[1] == '\xFE' )
|
||||
return wxBOM_UTF16LE;
|
||||
}
|
||||
|
||||
return wxBOM_None;
|
||||
}
|
||||
|
||||
void wxConvAuto::InitFromBOM(wxBOM bomType)
|
||||
{
|
||||
m_consumedBOM = false;
|
||||
|
||||
switch ( bomType )
|
||||
{
|
||||
case wxBOM_Unknown:
|
||||
wxFAIL_MSG( "shouldn't be called for this BOM type" );
|
||||
break;
|
||||
|
||||
case wxBOM_None:
|
||||
// use the default
|
||||
break;
|
||||
|
||||
case wxBOM_UTF32BE:
|
||||
m_conv = new wxMBConvUTF32BE;
|
||||
m_ownsConv = true;
|
||||
break;
|
||||
|
||||
case wxBOM_UTF32LE:
|
||||
m_conv = new wxMBConvUTF32LE;
|
||||
m_ownsConv = true;
|
||||
break;
|
||||
|
||||
case wxBOM_UTF16BE:
|
||||
m_conv = new wxMBConvUTF16BE;
|
||||
m_ownsConv = true;
|
||||
break;
|
||||
|
||||
case wxBOM_UTF16LE:
|
||||
m_conv = new wxMBConvUTF16LE;
|
||||
m_ownsConv = true;
|
||||
break;
|
||||
|
||||
case wxBOM_UTF8:
|
||||
InitWithUTF8();
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( "unknown BOM type" );
|
||||
}
|
||||
|
||||
if ( !m_conv )
|
||||
{
|
||||
// we end up here if there is no BOM or we didn't recognize it somehow
|
||||
// (this shouldn't happen but still don't crash if it does), so use the
|
||||
// default encoding
|
||||
InitWithUTF8();
|
||||
m_consumedBOM = true; // as there is nothing to consume
|
||||
}
|
||||
}
|
||||
|
||||
void wxConvAuto::SkipBOM(const char **src, size_t *len) const
|
||||
{
|
||||
int ofs;
|
||||
switch ( m_bomType )
|
||||
{
|
||||
case wxBOM_Unknown:
|
||||
wxFAIL_MSG( "shouldn't be called for this BOM type" );
|
||||
return;
|
||||
|
||||
case wxBOM_None:
|
||||
ofs = 0;
|
||||
break;
|
||||
|
||||
case wxBOM_UTF32BE:
|
||||
case wxBOM_UTF32LE:
|
||||
ofs = 4;
|
||||
break;
|
||||
|
||||
case wxBOM_UTF16BE:
|
||||
case wxBOM_UTF16LE:
|
||||
ofs = 2;
|
||||
break;
|
||||
|
||||
case wxBOM_UTF8:
|
||||
ofs = 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( "unknown BOM type" );
|
||||
return;
|
||||
}
|
||||
|
||||
*src += ofs;
|
||||
if ( *len != (size_t)-1 )
|
||||
*len -= ofs;
|
||||
}
|
||||
|
||||
bool wxConvAuto::InitFromInput(const char *src, size_t len)
|
||||
{
|
||||
m_bomType = DetectBOM(src, len == wxNO_LEN ? strlen(src) : len);
|
||||
if ( m_bomType == wxBOM_Unknown )
|
||||
return false;
|
||||
|
||||
InitFromBOM(m_bomType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// checks if the input can be the beginning of a valid UTF-8 sequence
|
||||
static bool wxCanBeUTF8SequencePrefix(const char *src, size_t len)
|
||||
{
|
||||
size_t i = 0;
|
||||
unsigned char l = tableUtf8Lengths[(unsigned char)src[i]];
|
||||
if ( !l )
|
||||
return false; // invalid leading byte
|
||||
while ( --l )
|
||||
{
|
||||
if ( ++i == len )
|
||||
return true; // truncated sequence
|
||||
if ( (src[i] & 0xC0) != 0x80 )
|
||||
return false; // invalid continuation byte
|
||||
}
|
||||
return false; // complete sequence
|
||||
}
|
||||
|
||||
size_t
|
||||
wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen,
|
||||
const char *src, size_t srcLen) const
|
||||
{
|
||||
// we check BOM and create the appropriate conversion the first time we're
|
||||
// called but we also need to ensure that the BOM is skipped not only
|
||||
// during this initial call but also during the first call with non-NULL
|
||||
// dst as typically we're first called with NULL dst to calculate the
|
||||
// needed buffer size
|
||||
wxConvAuto *self = const_cast<wxConvAuto *>(this);
|
||||
|
||||
|
||||
if ( !m_conv )
|
||||
{
|
||||
if ( !self->InitFromInput(src, srcLen) )
|
||||
{
|
||||
// there is not enough data to determine whether we have a BOM or
|
||||
// not, so fail for now -- the caller is supposed to call us again
|
||||
// with more data
|
||||
return wxCONV_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !m_consumedBOM )
|
||||
{
|
||||
SkipBOM(&src, &srcLen);
|
||||
if ( srcLen == 0 )
|
||||
{
|
||||
// there is nothing left except the BOM so we'd return 0 below but
|
||||
// this is unexpected: decoding a non-empty string must either fail
|
||||
// or return something non-empty, in particular this would break
|
||||
// the code in wxTextInputStream::NextChar()
|
||||
//
|
||||
// so still return an error as we need some more data to be able to
|
||||
// decode it
|
||||
return wxCONV_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
// try to convert using the auto-detected encoding
|
||||
size_t rc = m_conv->ToWChar(dst, dstLen, src, srcLen);
|
||||
if ( rc == wxCONV_FAILED && m_bomType == wxBOM_None && !m_ownsConv )
|
||||
{
|
||||
// we may need more bytes before we can decode the input, don't switch
|
||||
// to the fall-back conversion in this case as it would prevent us from
|
||||
// decoding UTF-8 input when fed it byte by byte, as done by
|
||||
// wxTextInputStream, for example
|
||||
// up to 2 extra bytes are needed for inputs that start with null bytes
|
||||
// that look like the start of UTF-32BE BOM, but can be in UTF-8 too
|
||||
size_t nNull = 0;
|
||||
if ( srcLen != wxNO_LEN && srcLen >= 2 && !src[0] )
|
||||
nNull = ( src[1]? 1 : 2 );
|
||||
if ( srcLen < nNull + m_conv->GetMaxCharLen() &&
|
||||
wxCanBeUTF8SequencePrefix(src + nNull, srcLen - nNull) )
|
||||
return wxCONV_FAILED;
|
||||
|
||||
// if the conversion failed but we didn't really detect anything and
|
||||
// simply tried UTF-8 by default, retry it using the fall-back
|
||||
if ( m_encDefault == wxFONTENCODING_DEFAULT )
|
||||
self->m_encDefault = GetFallbackEncoding();
|
||||
if ( m_encDefault != wxFONTENCODING_MAX )
|
||||
{
|
||||
self->m_conv = new wxCSConv(m_encDefault);
|
||||
self->m_ownsConv = true;
|
||||
|
||||
rc = m_conv->ToWChar(dst, dstLen, src, srcLen);
|
||||
}
|
||||
}
|
||||
|
||||
// don't skip the BOM again the next time if we really consumed it
|
||||
if ( rc != wxCONV_FAILED && dst && !m_consumedBOM )
|
||||
self->m_consumedBOM = true;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t
|
||||
wxConvAuto::FromWChar(char *dst, size_t dstLen,
|
||||
const wchar_t *src, size_t srcLen) const
|
||||
{
|
||||
if ( !m_conv )
|
||||
{
|
||||
// default to UTF-8 for the multibyte output
|
||||
const_cast<wxConvAuto *>(this)->InitWithUTF8();
|
||||
}
|
||||
|
||||
return m_conv->FromWChar(dst, dstLen, src, srcLen);
|
||||
}
|
||||
|
||||
wxFontEncoding wxConvAuto::GetEncoding() const
|
||||
{
|
||||
switch ( m_bomType )
|
||||
{
|
||||
case wxBOM_UTF32BE:
|
||||
return wxFONTENCODING_UTF32BE;
|
||||
case wxBOM_UTF32LE:
|
||||
return wxFONTENCODING_UTF32LE;
|
||||
case wxBOM_UTF16BE:
|
||||
return wxFONTENCODING_UTF16BE;
|
||||
case wxBOM_UTF16LE:
|
||||
return wxFONTENCODING_UTF16LE;
|
||||
case wxBOM_UTF8:
|
||||
return wxFONTENCODING_UTF8;
|
||||
|
||||
case wxBOM_Unknown:
|
||||
case wxBOM_None:
|
||||
if ( !m_conv )
|
||||
return wxFONTENCODING_MAX;
|
||||
else if ( !m_ownsConv )
|
||||
return wxFONTENCODING_UTF8;
|
||||
else
|
||||
return m_encDefault;
|
||||
}
|
||||
|
||||
wxFAIL_MSG( "unknown BOM type" );
|
||||
return wxFONTENCODING_MAX;
|
||||
}
|
||||
@@ -0,0 +1,499 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/cshelp.cpp
|
||||
// Purpose: Context sensitive help class implementation
|
||||
// Author: Julian Smart, Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 08/09/2000
|
||||
// Copyright: (c) 2000 Julian Smart, Vadim Zeitlin
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_HELP
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/app.h"
|
||||
#include "wx/module.h"
|
||||
#endif
|
||||
|
||||
#include "wx/tipwin.h"
|
||||
#include "wx/cshelp.h"
|
||||
|
||||
#if wxUSE_MS_HTML_HELP
|
||||
#include "wx/msw/helpchm.h" // for ShowContextHelpPopup
|
||||
#include "wx/utils.h" // for wxGetMousePosition()
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxContextHelpEvtHandler private class
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// This class exists in order to eat events until the left mouse button is
|
||||
// pressed
|
||||
class wxContextHelpEvtHandler: public wxEvtHandler
|
||||
{
|
||||
public:
|
||||
wxContextHelpEvtHandler(wxContextHelp* contextHelp)
|
||||
{
|
||||
m_contextHelp = contextHelp;
|
||||
}
|
||||
|
||||
virtual bool ProcessEvent(wxEvent& event) wxOVERRIDE;
|
||||
|
||||
//// Data
|
||||
wxContextHelp* m_contextHelp;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler);
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxContextHelp
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Invokes context-sensitive help
|
||||
*/
|
||||
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject);
|
||||
|
||||
wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp)
|
||||
{
|
||||
m_inHelp = false;
|
||||
|
||||
if (beginHelp)
|
||||
BeginContextHelp(win);
|
||||
}
|
||||
|
||||
wxContextHelp::~wxContextHelp()
|
||||
{
|
||||
if (m_inHelp)
|
||||
EndContextHelp();
|
||||
}
|
||||
|
||||
// Not currently needed, but on some systems capture may not work as
|
||||
// expected so we'll leave it here for now.
|
||||
#ifdef __WXMOTIF__
|
||||
static void wxPushOrPopEventHandlers(wxContextHelp* help, wxWindow* win, bool push)
|
||||
{
|
||||
if (push)
|
||||
win->PushEventHandler(new wxContextHelpEvtHandler(help));
|
||||
else
|
||||
win->PopEventHandler(true);
|
||||
|
||||
wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
|
||||
while (node)
|
||||
{
|
||||
wxWindow* child = node->GetData();
|
||||
wxPushOrPopEventHandlers(help, child, push);
|
||||
|
||||
node = node->GetNext();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Begin 'context help mode'
|
||||
bool wxContextHelp::BeginContextHelp(wxWindow* win)
|
||||
{
|
||||
if (!win)
|
||||
win = wxTheApp->GetTopWindow();
|
||||
if (!win)
|
||||
return false;
|
||||
|
||||
wxCursor cursor(wxCURSOR_QUESTION_ARROW);
|
||||
wxCursor oldCursor = win->GetCursor();
|
||||
win->SetCursor(cursor);
|
||||
|
||||
#ifdef __WXMAC__
|
||||
wxSetCursor(cursor);
|
||||
#endif
|
||||
|
||||
m_status = false;
|
||||
|
||||
#ifdef __WXMOTIF__
|
||||
wxPushOrPopEventHandlers(this, win, true);
|
||||
#else
|
||||
win->PushEventHandler(new wxContextHelpEvtHandler(this));
|
||||
#endif
|
||||
|
||||
win->CaptureMouse();
|
||||
|
||||
EventLoop();
|
||||
|
||||
win->ReleaseMouse();
|
||||
|
||||
#ifdef __WXMOTIF__
|
||||
wxPushOrPopEventHandlers(this, win, false);
|
||||
#else
|
||||
win->PopEventHandler(true);
|
||||
#endif
|
||||
|
||||
win->SetCursor(oldCursor);
|
||||
|
||||
#ifdef __WXMAC__
|
||||
wxSetCursor(wxNullCursor);
|
||||
#endif
|
||||
|
||||
if (m_status)
|
||||
{
|
||||
wxPoint pt;
|
||||
wxWindow* winAtPtr = wxFindWindowAtPointer(pt);
|
||||
|
||||
#if 0
|
||||
if (winAtPtr)
|
||||
{
|
||||
printf("Picked %s (%d)\n", winAtPtr->GetName().c_str(),
|
||||
winAtPtr->GetId());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (winAtPtr)
|
||||
DispatchEvent(winAtPtr, pt);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxContextHelp::EndContextHelp()
|
||||
{
|
||||
m_inHelp = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxContextHelp::EventLoop()
|
||||
{
|
||||
m_inHelp = true;
|
||||
|
||||
while ( m_inHelp )
|
||||
{
|
||||
if (wxTheApp->Pending())
|
||||
{
|
||||
wxTheApp->Dispatch();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxTheApp->ProcessIdle();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event)
|
||||
{
|
||||
if (event.GetEventType() == wxEVT_LEFT_DOWN)
|
||||
{
|
||||
m_contextHelp->SetStatus(true);
|
||||
m_contextHelp->EndContextHelp();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((event.GetEventType() == wxEVT_CHAR) ||
|
||||
(event.GetEventType() == wxEVT_KEY_DOWN) ||
|
||||
(event.GetEventType() == wxEVT_ACTIVATE) ||
|
||||
(event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED))
|
||||
{
|
||||
// May have already been set to true by a left-click
|
||||
//m_contextHelp->SetStatus(false);
|
||||
m_contextHelp->EndContextHelp();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((event.GetEventType() == wxEVT_PAINT) ||
|
||||
(event.GetEventType() == wxEVT_ERASE_BACKGROUND))
|
||||
{
|
||||
event.Skip();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dispatch the help event to the relevant window
|
||||
bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt)
|
||||
{
|
||||
wxCHECK_MSG( win, false, wxT("win parameter can't be NULL") );
|
||||
|
||||
wxHelpEvent helpEvent(wxEVT_HELP, win->GetId(), pt,
|
||||
wxHelpEvent::Origin_HelpButton);
|
||||
helpEvent.SetEventObject(win);
|
||||
|
||||
return win->GetEventHandler()->ProcessEvent(helpEvent);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxContextHelpButton
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* wxContextHelpButton
|
||||
* You can add this to your dialogs (especially on non-Windows platforms)
|
||||
* to put the application into context help mode.
|
||||
*/
|
||||
|
||||
static const char * csquery_xpm[] = {
|
||||
"12 11 2 1",
|
||||
" c None",
|
||||
". c #000000",
|
||||
" ",
|
||||
" .... ",
|
||||
" .. .. ",
|
||||
" .. .. ",
|
||||
" .. ",
|
||||
" .. ",
|
||||
" .. ",
|
||||
" ",
|
||||
" .. ",
|
||||
" .. ",
|
||||
" "};
|
||||
|
||||
|
||||
wxIMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton);
|
||||
|
||||
wxBEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton)
|
||||
EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
bool wxContextHelpButton::Create(wxWindow* parent,
|
||||
wxWindowID id,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style)
|
||||
{
|
||||
return wxBitmapButton::Create(parent, id,
|
||||
wxBitmap(csquery_xpm),
|
||||
pos, size, style);
|
||||
}
|
||||
|
||||
void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
wxContextHelp contextHelp(GetParent());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxHelpProvider
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxHelpProvider *wxHelpProvider::ms_helpProvider = NULL;
|
||||
|
||||
// trivial implementation of some methods which we don't want to make pure
|
||||
// virtual for convenience
|
||||
|
||||
void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window),
|
||||
const wxString& WXUNUSED(text))
|
||||
{
|
||||
}
|
||||
|
||||
void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id),
|
||||
const wxString& WXUNUSED(text))
|
||||
{
|
||||
}
|
||||
|
||||
// removes the association
|
||||
void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window))
|
||||
{
|
||||
}
|
||||
|
||||
wxHelpProvider::~wxHelpProvider()
|
||||
{
|
||||
}
|
||||
|
||||
wxString wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase *window)
|
||||
{
|
||||
if ( m_helptextAtPoint != wxDefaultPosition ||
|
||||
m_helptextOrigin != wxHelpEvent::Origin_Unknown )
|
||||
{
|
||||
wxCHECK_MSG( window, wxEmptyString, wxT("window must not be NULL") );
|
||||
|
||||
wxPoint pt = m_helptextAtPoint;
|
||||
wxHelpEvent::Origin origin = m_helptextOrigin;
|
||||
|
||||
m_helptextAtPoint = wxDefaultPosition;
|
||||
m_helptextOrigin = wxHelpEvent::Origin_Unknown;
|
||||
|
||||
return window->GetHelpTextAtPoint(pt, origin);
|
||||
}
|
||||
|
||||
return GetHelp(window);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxSimpleHelpProvider
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define WINHASH_KEY(w) wxPtrToUInt(w)
|
||||
|
||||
wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
|
||||
{
|
||||
wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window));
|
||||
|
||||
if ( it == m_hashWindows.end() )
|
||||
{
|
||||
it = m_hashIds.find(window->GetId());
|
||||
if ( it == m_hashIds.end() )
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
|
||||
{
|
||||
m_hashWindows.erase(WINHASH_KEY(window));
|
||||
m_hashWindows[WINHASH_KEY(window)] = text;
|
||||
}
|
||||
|
||||
void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
|
||||
{
|
||||
wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id;
|
||||
m_hashIds.erase(key);
|
||||
m_hashIds[key] = text;
|
||||
}
|
||||
|
||||
// removes the association
|
||||
void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
|
||||
{
|
||||
m_hashWindows.erase(WINHASH_KEY(window));
|
||||
}
|
||||
|
||||
bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
|
||||
{
|
||||
#if wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
|
||||
#if wxUSE_MS_HTML_HELP
|
||||
// m_helptextAtPoint will be reset by GetHelpTextMaybeAtPoint(), stash it
|
||||
const wxPoint posTooltip = m_helptextAtPoint;
|
||||
#endif // wxUSE_MS_HTML_HELP
|
||||
|
||||
const wxString text = GetHelpTextMaybeAtPoint(window);
|
||||
|
||||
if ( !text.empty() )
|
||||
{
|
||||
// use the native help popup style if it's available
|
||||
#if wxUSE_MS_HTML_HELP
|
||||
if ( !wxCHMHelpController::ShowContextHelpPopup
|
||||
(
|
||||
text,
|
||||
posTooltip,
|
||||
(wxWindow *)window
|
||||
) )
|
||||
#endif // wxUSE_MS_HTML_HELP
|
||||
{
|
||||
#if wxUSE_TIPWINDOW
|
||||
static wxTipWindow* s_tipWindow = NULL;
|
||||
|
||||
if ( s_tipWindow )
|
||||
{
|
||||
// Prevent s_tipWindow being nulled in OnIdle, thereby removing
|
||||
// the chance for the window to be closed by ShowHelp
|
||||
s_tipWindow->SetTipWindowPtr(NULL);
|
||||
s_tipWindow->Close();
|
||||
}
|
||||
|
||||
s_tipWindow = new wxTipWindow((wxWindow *)window, text,
|
||||
100, &s_tipWindow);
|
||||
#else // !wxUSE_TIPWINDOW
|
||||
// we tried wxCHMHelpController but it failed and we don't have
|
||||
// wxTipWindow to fall back on, so
|
||||
return false;
|
||||
#endif // wxUSE_TIPWINDOW
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#else // !wxUSE_MS_HTML_HELP && !wxUSE_TIPWINDOW
|
||||
wxUnusedVar(window);
|
||||
#endif // wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxHelpControllerHelpProvider
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
|
||||
{
|
||||
m_helpController = hc;
|
||||
}
|
||||
|
||||
bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
|
||||
{
|
||||
const wxString text = GetHelpTextMaybeAtPoint(window);
|
||||
|
||||
if ( text.empty() )
|
||||
return false;
|
||||
|
||||
if ( m_helpController )
|
||||
{
|
||||
// if it's a numeric topic, show it
|
||||
long topic;
|
||||
if ( text.ToLong(&topic) )
|
||||
return m_helpController->DisplayContextPopup(topic);
|
||||
|
||||
// otherwise show the text directly
|
||||
if ( m_helpController->DisplayTextPopup(text, wxGetMousePosition()) )
|
||||
return true;
|
||||
}
|
||||
|
||||
// if there is no help controller or it's not capable of showing the help,
|
||||
// fallback to the default method
|
||||
return wxSimpleHelpProvider::ShowHelp(window);
|
||||
}
|
||||
|
||||
// Convenience function for turning context id into wxString
|
||||
wxString wxContextId(int id)
|
||||
{
|
||||
return wxString::Format(wxT("%d"), id);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxHelpProviderModule: module responsible for cleaning up help provider.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxHelpProviderModule : public wxModule
|
||||
{
|
||||
public:
|
||||
bool OnInit() wxOVERRIDE;
|
||||
void OnExit() wxOVERRIDE;
|
||||
|
||||
private:
|
||||
wxDECLARE_DYNAMIC_CLASS(wxHelpProviderModule);
|
||||
};
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule);
|
||||
|
||||
bool wxHelpProviderModule::OnInit()
|
||||
{
|
||||
// Probably we don't want to do anything by default,
|
||||
// since it could pull in extra code
|
||||
// wxHelpProvider::Set(new wxSimpleHelpProvider);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxHelpProviderModule::OnExit()
|
||||
{
|
||||
if (wxHelpProvider::Get())
|
||||
{
|
||||
delete wxHelpProvider::Get();
|
||||
wxHelpProvider::Set(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_HELP
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,849 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/datstrm.cpp
|
||||
// Purpose: Data stream classes
|
||||
// Author: Guilhem Lavaux
|
||||
// Modified by: Mickael Gilabert
|
||||
// Created: 28/06/98
|
||||
// Copyright: (c) Guilhem Lavaux
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_STREAMS
|
||||
|
||||
#include "wx/datstrm.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/math.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// helper unions used to swap bytes of floats and doubles
|
||||
union Float32Data
|
||||
{
|
||||
wxFloat32 f;
|
||||
wxUint32 i;
|
||||
};
|
||||
|
||||
union Float64Data
|
||||
{
|
||||
wxFloat64 f;
|
||||
wxUint32 i[2];
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDataStreamBase
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxDataStreamBase::wxDataStreamBase(const wxMBConv& conv)
|
||||
#if wxUSE_UNICODE
|
||||
: m_conv(conv.Clone())
|
||||
#endif // wxUSE_UNICODE
|
||||
{
|
||||
// It is unused in non-Unicode build, so suppress a warning there.
|
||||
wxUnusedVar(conv);
|
||||
|
||||
m_be_order = false;
|
||||
|
||||
// For compatibility with the existing data files, we use extended
|
||||
// precision if it is available, i.e. if wxUSE_APPLE_IEEE is on.
|
||||
#if wxUSE_APPLE_IEEE
|
||||
m_useExtendedPrecision = true;
|
||||
#endif // wxUSE_APPLE_IEEE
|
||||
}
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
void wxDataStreamBase::SetConv( const wxMBConv &conv )
|
||||
{
|
||||
delete m_conv;
|
||||
m_conv = conv.Clone();
|
||||
}
|
||||
#endif
|
||||
|
||||
wxDataStreamBase::~wxDataStreamBase()
|
||||
{
|
||||
#if wxUSE_UNICODE
|
||||
delete m_conv;
|
||||
#endif // wxUSE_UNICODE
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// wxDataInputStream
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
wxDataInputStream::wxDataInputStream(wxInputStream& s, const wxMBConv& conv)
|
||||
: wxDataStreamBase(conv),
|
||||
m_input(&s)
|
||||
{
|
||||
}
|
||||
|
||||
#if wxHAS_INT64
|
||||
wxUint64 wxDataInputStream::Read64()
|
||||
{
|
||||
wxUint64 tmp;
|
||||
Read64(&tmp, 1);
|
||||
return tmp;
|
||||
}
|
||||
#endif // wxHAS_INT64
|
||||
|
||||
wxUint32 wxDataInputStream::Read32()
|
||||
{
|
||||
wxUint32 i32;
|
||||
|
||||
m_input->Read(&i32, 4);
|
||||
|
||||
if (m_be_order)
|
||||
return wxUINT32_SWAP_ON_LE(i32);
|
||||
else
|
||||
return wxUINT32_SWAP_ON_BE(i32);
|
||||
}
|
||||
|
||||
wxUint16 wxDataInputStream::Read16()
|
||||
{
|
||||
wxUint16 i16;
|
||||
|
||||
m_input->Read(&i16, 2);
|
||||
|
||||
if (m_be_order)
|
||||
return wxUINT16_SWAP_ON_LE(i16);
|
||||
else
|
||||
return wxUINT16_SWAP_ON_BE(i16);
|
||||
}
|
||||
|
||||
wxUint8 wxDataInputStream::Read8()
|
||||
{
|
||||
wxUint8 buf;
|
||||
|
||||
m_input->Read(&buf, 1);
|
||||
return (wxUint8)buf;
|
||||
}
|
||||
|
||||
double wxDataInputStream::ReadDouble()
|
||||
{
|
||||
#if wxUSE_APPLE_IEEE
|
||||
if ( m_useExtendedPrecision )
|
||||
{
|
||||
char buf[10];
|
||||
|
||||
m_input->Read(buf, 10);
|
||||
return wxConvertFromIeeeExtended((const wxInt8 *)buf);
|
||||
}
|
||||
else
|
||||
#endif // wxUSE_APPLE_IEEE
|
||||
{
|
||||
Float64Data floatData;
|
||||
|
||||
if ( m_be_order == (wxBYTE_ORDER == wxBIG_ENDIAN) )
|
||||
{
|
||||
floatData.i[0] = Read32();
|
||||
floatData.i[1] = Read32();
|
||||
}
|
||||
else
|
||||
{
|
||||
floatData.i[1] = Read32();
|
||||
floatData.i[0] = Read32();
|
||||
}
|
||||
|
||||
return static_cast<double>(floatData.f);
|
||||
}
|
||||
}
|
||||
|
||||
float wxDataInputStream::ReadFloat()
|
||||
{
|
||||
#if wxUSE_APPLE_IEEE
|
||||
if ( m_useExtendedPrecision )
|
||||
{
|
||||
return (float)ReadDouble();
|
||||
}
|
||||
else
|
||||
#endif // wxUSE_APPLE_IEEE
|
||||
{
|
||||
Float32Data floatData;
|
||||
|
||||
floatData.i = Read32();
|
||||
return static_cast<float>(floatData.f);
|
||||
}
|
||||
}
|
||||
|
||||
wxString wxDataInputStream::ReadString()
|
||||
{
|
||||
wxString ret;
|
||||
|
||||
const size_t len = Read32();
|
||||
if ( len > 0 )
|
||||
{
|
||||
#if wxUSE_UNICODE
|
||||
wxCharBuffer tmp(len);
|
||||
if ( tmp )
|
||||
{
|
||||
m_input->Read(tmp.data(), len);
|
||||
ret = m_conv->cMB2WC(tmp.data(), len, NULL);
|
||||
}
|
||||
#else
|
||||
wxStringBuffer buf(ret, len);
|
||||
if ( buf )
|
||||
m_input->Read(buf, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if wxUSE_LONGLONG
|
||||
|
||||
template <class T>
|
||||
static
|
||||
void DoReadLL(T *buffer, size_t size, wxInputStream *input, bool be_order)
|
||||
{
|
||||
typedef T DataType;
|
||||
unsigned char *pchBuffer = new unsigned char[size * 8];
|
||||
// TODO: Check for overflow when size is of type uint and is > than 512m
|
||||
input->Read(pchBuffer, size * 8);
|
||||
size_t idx_base = 0;
|
||||
if ( be_order )
|
||||
{
|
||||
for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex )
|
||||
{
|
||||
buffer[uiIndex] = 0l;
|
||||
for ( unsigned ui = 0; ui != 8; ++ui )
|
||||
{
|
||||
buffer[uiIndex] = buffer[uiIndex] * 256l +
|
||||
DataType((unsigned long) pchBuffer[idx_base + ui]);
|
||||
}
|
||||
|
||||
idx_base += 8;
|
||||
}
|
||||
}
|
||||
else // little endian
|
||||
{
|
||||
for ( size_t uiIndex=0; uiIndex!=size; ++uiIndex )
|
||||
{
|
||||
buffer[uiIndex] = 0l;
|
||||
for ( unsigned ui=0; ui!=8; ++ui )
|
||||
buffer[uiIndex] = buffer[uiIndex] * 256l +
|
||||
DataType((unsigned long) pchBuffer[idx_base + 7 - ui]);
|
||||
idx_base += 8;
|
||||
}
|
||||
}
|
||||
delete[] pchBuffer;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void DoWriteLL(const T *buffer, size_t size, wxOutputStream *output, bool be_order)
|
||||
{
|
||||
typedef T DataType;
|
||||
unsigned char *pchBuffer = new unsigned char[size * 8];
|
||||
size_t idx_base = 0;
|
||||
if ( be_order )
|
||||
{
|
||||
for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex )
|
||||
{
|
||||
DataType i64 = buffer[uiIndex];
|
||||
for ( unsigned ui = 0; ui != 8; ++ui )
|
||||
{
|
||||
pchBuffer[idx_base + 7 - ui] =
|
||||
(unsigned char) (i64.GetLo() & 255l);
|
||||
i64 >>= 8l;
|
||||
}
|
||||
|
||||
idx_base += 8;
|
||||
}
|
||||
}
|
||||
else // little endian
|
||||
{
|
||||
for ( size_t uiIndex=0; uiIndex != size; ++uiIndex )
|
||||
{
|
||||
DataType i64 = buffer[uiIndex];
|
||||
for (unsigned ui=0; ui!=8; ++ui)
|
||||
{
|
||||
pchBuffer[idx_base + ui] =
|
||||
(unsigned char) (i64.GetLo() & 255l);
|
||||
i64 >>= 8l;
|
||||
}
|
||||
|
||||
idx_base += 8;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check for overflow when size is of type uint and is > than 512m
|
||||
output->Write(pchBuffer, size * 8);
|
||||
delete[] pchBuffer;
|
||||
}
|
||||
|
||||
#endif // wxUSE_LONGLONG
|
||||
|
||||
#ifdef wxLongLong_t
|
||||
|
||||
template <class T>
|
||||
static
|
||||
void DoReadI64(T *buffer, size_t size, wxInputStream *input, bool be_order)
|
||||
{
|
||||
typedef T DataType;
|
||||
unsigned char *pchBuffer = (unsigned char*) buffer;
|
||||
// TODO: Check for overflow when size is of type uint and is > than 512m
|
||||
input->Read(pchBuffer, size * 8);
|
||||
if ( be_order )
|
||||
{
|
||||
for ( wxUint32 i = 0; i < size; i++ )
|
||||
{
|
||||
DataType v = wxUINT64_SWAP_ON_LE(*buffer);
|
||||
*(buffer++) = v;
|
||||
}
|
||||
}
|
||||
else // little endian
|
||||
{
|
||||
for ( wxUint32 i=0; i<size; i++ )
|
||||
{
|
||||
DataType v = wxUINT64_SWAP_ON_BE(*buffer);
|
||||
*(buffer++) = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static
|
||||
void DoWriteI64(const T *buffer, size_t size, wxOutputStream *output, bool be_order)
|
||||
{
|
||||
typedef T DataType;
|
||||
if ( be_order )
|
||||
{
|
||||
for ( size_t i = 0; i < size; i++ )
|
||||
{
|
||||
DataType i64 = wxUINT64_SWAP_ON_LE(*buffer);
|
||||
buffer++;
|
||||
output->Write(&i64, 8);
|
||||
}
|
||||
}
|
||||
else // little endian
|
||||
{
|
||||
for ( size_t i=0; i < size; i++ )
|
||||
{
|
||||
DataType i64 = wxUINT64_SWAP_ON_BE(*buffer);
|
||||
buffer++;
|
||||
output->Write(&i64, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxLongLong_t
|
||||
|
||||
|
||||
#if wxHAS_INT64
|
||||
void wxDataInputStream::Read64(wxUint64 *buffer, size_t size)
|
||||
{
|
||||
#ifndef wxLongLong_t
|
||||
DoReadLL(buffer, size, m_input, m_be_order);
|
||||
#else
|
||||
DoReadI64(buffer, size, m_input, m_be_order);
|
||||
#endif
|
||||
}
|
||||
|
||||
void wxDataInputStream::Read64(wxInt64 *buffer, size_t size)
|
||||
{
|
||||
#ifndef wxLongLong_t
|
||||
DoReadLL(buffer, size, m_input, m_be_order);
|
||||
#else
|
||||
DoReadI64(buffer, size, m_input, m_be_order);
|
||||
#endif
|
||||
}
|
||||
#endif // wxHAS_INT64
|
||||
|
||||
#if defined(wxLongLong_t) && wxUSE_LONGLONG
|
||||
void wxDataInputStream::Read64(wxULongLong *buffer, size_t size)
|
||||
{
|
||||
DoReadLL(buffer, size, m_input, m_be_order);
|
||||
}
|
||||
|
||||
void wxDataInputStream::Read64(wxLongLong *buffer, size_t size)
|
||||
{
|
||||
DoReadLL(buffer, size, m_input, m_be_order);
|
||||
}
|
||||
#endif // wxLongLong_t
|
||||
|
||||
#if wxUSE_LONGLONG
|
||||
void wxDataInputStream::ReadLL(wxULongLong *buffer, size_t size)
|
||||
{
|
||||
DoReadLL(buffer, size, m_input, m_be_order);
|
||||
}
|
||||
|
||||
void wxDataInputStream::ReadLL(wxLongLong *buffer, size_t size)
|
||||
{
|
||||
DoReadLL(buffer, size, m_input, m_be_order);
|
||||
}
|
||||
|
||||
wxLongLong wxDataInputStream::ReadLL(void)
|
||||
{
|
||||
wxLongLong ll;
|
||||
DoReadLL(&ll, (size_t)1, m_input, m_be_order);
|
||||
return ll;
|
||||
}
|
||||
#endif // wxUSE_LONGLONG
|
||||
|
||||
void wxDataInputStream::Read32(wxUint32 *buffer, size_t size)
|
||||
{
|
||||
m_input->Read(buffer, size * 4);
|
||||
|
||||
if (m_be_order)
|
||||
{
|
||||
for (wxUint32 i=0; i<size; i++)
|
||||
{
|
||||
wxUint32 v = wxUINT32_SWAP_ON_LE(*buffer);
|
||||
*(buffer++) = v;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (wxUint32 i=0; i<size; i++)
|
||||
{
|
||||
wxUint32 v = wxUINT32_SWAP_ON_BE(*buffer);
|
||||
*(buffer++) = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxDataInputStream::Read16(wxUint16 *buffer, size_t size)
|
||||
{
|
||||
m_input->Read(buffer, size * 2);
|
||||
|
||||
if (m_be_order)
|
||||
{
|
||||
for (wxUint32 i=0; i<size; i++)
|
||||
{
|
||||
wxUint16 v = wxUINT16_SWAP_ON_LE(*buffer);
|
||||
*(buffer++) = v;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (wxUint32 i=0; i<size; i++)
|
||||
{
|
||||
wxUint16 v = wxUINT16_SWAP_ON_BE(*buffer);
|
||||
*(buffer++) = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxDataInputStream::Read8(wxUint8 *buffer, size_t size)
|
||||
{
|
||||
m_input->Read(buffer, size);
|
||||
}
|
||||
|
||||
void wxDataInputStream::ReadDouble(double *buffer, size_t size)
|
||||
{
|
||||
for (wxUint32 i=0; i<size; i++)
|
||||
{
|
||||
*(buffer++) = ReadDouble();
|
||||
}
|
||||
}
|
||||
|
||||
void wxDataInputStream::ReadFloat(float *buffer, size_t size)
|
||||
{
|
||||
for (wxUint32 i=0; i<size; i++)
|
||||
{
|
||||
*(buffer++) = ReadFloat();
|
||||
}
|
||||
}
|
||||
|
||||
wxDataInputStream& wxDataInputStream::operator>>(wxString& s)
|
||||
{
|
||||
s = ReadString();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataInputStream& wxDataInputStream::operator>>(wxInt8& c)
|
||||
{
|
||||
c = (wxInt8)Read8();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataInputStream& wxDataInputStream::operator>>(wxInt16& i)
|
||||
{
|
||||
i = (wxInt16)Read16();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataInputStream& wxDataInputStream::operator>>(wxInt32& i)
|
||||
{
|
||||
i = (wxInt32)Read32();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataInputStream& wxDataInputStream::operator>>(wxUint8& c)
|
||||
{
|
||||
c = Read8();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataInputStream& wxDataInputStream::operator>>(wxUint16& i)
|
||||
{
|
||||
i = Read16();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataInputStream& wxDataInputStream::operator>>(wxUint32& i)
|
||||
{
|
||||
i = Read32();
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if wxHAS_INT64
|
||||
wxDataInputStream& wxDataInputStream::operator>>(wxUint64& i)
|
||||
{
|
||||
i = Read64();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataInputStream& wxDataInputStream::operator>>(wxInt64& i)
|
||||
{
|
||||
i = Read64();
|
||||
return *this;
|
||||
}
|
||||
#endif // wxHAS_INT64
|
||||
|
||||
#if defined(wxLongLong_t) && wxUSE_LONGLONG
|
||||
wxDataInputStream& wxDataInputStream::operator>>(wxULongLong& i)
|
||||
{
|
||||
i = ReadLL();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataInputStream& wxDataInputStream::operator>>(wxLongLong& i)
|
||||
{
|
||||
i = ReadLL();
|
||||
return *this;
|
||||
}
|
||||
#endif // wxLongLong_t
|
||||
|
||||
wxDataInputStream& wxDataInputStream::operator>>(double& d)
|
||||
{
|
||||
d = ReadDouble();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataInputStream& wxDataInputStream::operator>>(float& f)
|
||||
{
|
||||
f = ReadFloat();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// wxDataOutputStream
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
wxDataOutputStream::wxDataOutputStream(wxOutputStream& s, const wxMBConv& conv)
|
||||
: wxDataStreamBase(conv),
|
||||
m_output(&s)
|
||||
{
|
||||
}
|
||||
|
||||
#if wxHAS_INT64
|
||||
void wxDataOutputStream::Write64(wxUint64 i)
|
||||
{
|
||||
Write64(&i, 1);
|
||||
}
|
||||
|
||||
void wxDataOutputStream::Write64(wxInt64 i)
|
||||
{
|
||||
Write64(&i, 1);
|
||||
}
|
||||
#endif // wxHAS_INT64
|
||||
|
||||
void wxDataOutputStream::Write32(wxUint32 i)
|
||||
{
|
||||
wxUint32 i32;
|
||||
|
||||
if (m_be_order)
|
||||
i32 = wxUINT32_SWAP_ON_LE(i);
|
||||
else
|
||||
i32 = wxUINT32_SWAP_ON_BE(i);
|
||||
m_output->Write(&i32, 4);
|
||||
}
|
||||
|
||||
void wxDataOutputStream::Write16(wxUint16 i)
|
||||
{
|
||||
wxUint16 i16;
|
||||
|
||||
if (m_be_order)
|
||||
i16 = wxUINT16_SWAP_ON_LE(i);
|
||||
else
|
||||
i16 = wxUINT16_SWAP_ON_BE(i);
|
||||
|
||||
m_output->Write(&i16, 2);
|
||||
}
|
||||
|
||||
void wxDataOutputStream::Write8(wxUint8 i)
|
||||
{
|
||||
m_output->Write(&i, 1);
|
||||
}
|
||||
|
||||
void wxDataOutputStream::WriteString(const wxString& string)
|
||||
{
|
||||
#if wxUSE_UNICODE
|
||||
const wxWX2MBbuf buf = string.mb_str(*m_conv);
|
||||
size_t len = buf.length();
|
||||
#else
|
||||
const wxWX2MBbuf buf = string.mb_str();
|
||||
size_t len = string.size();
|
||||
#endif
|
||||
Write32(len);
|
||||
if (len > 0)
|
||||
m_output->Write(buf, len);
|
||||
}
|
||||
|
||||
void wxDataOutputStream::WriteDouble(double d)
|
||||
{
|
||||
#if wxUSE_APPLE_IEEE
|
||||
if ( m_useExtendedPrecision )
|
||||
{
|
||||
char buf[10];
|
||||
|
||||
wxConvertToIeeeExtended(d, (wxInt8 *)buf);
|
||||
m_output->Write(buf, 10);
|
||||
}
|
||||
else
|
||||
#endif // wxUSE_APPLE_IEEE
|
||||
{
|
||||
Float64Data floatData;
|
||||
|
||||
floatData.f = (wxFloat64)d;
|
||||
|
||||
if ( m_be_order == (wxBYTE_ORDER == wxBIG_ENDIAN) )
|
||||
{
|
||||
Write32(floatData.i[0]);
|
||||
Write32(floatData.i[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write32(floatData.i[1]);
|
||||
Write32(floatData.i[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxDataOutputStream::WriteFloat(float f)
|
||||
{
|
||||
#if wxUSE_APPLE_IEEE
|
||||
if ( m_useExtendedPrecision )
|
||||
{
|
||||
WriteDouble((double)f);
|
||||
}
|
||||
else
|
||||
#endif // wxUSE_APPLE_IEEE
|
||||
{
|
||||
Float32Data floatData;
|
||||
|
||||
floatData.f = (wxFloat32)f;
|
||||
Write32(floatData.i);
|
||||
}
|
||||
}
|
||||
|
||||
#if wxHAS_INT64
|
||||
void wxDataOutputStream::Write64(const wxUint64 *buffer, size_t size)
|
||||
{
|
||||
#ifndef wxLongLong_t
|
||||
DoWriteLL(buffer, size, m_output, m_be_order);
|
||||
#else
|
||||
DoWriteI64(buffer, size, m_output, m_be_order);
|
||||
#endif
|
||||
}
|
||||
|
||||
void wxDataOutputStream::Write64(const wxInt64 *buffer, size_t size)
|
||||
{
|
||||
#ifndef wxLongLong_t
|
||||
DoWriteLL(buffer, size, m_output, m_be_order);
|
||||
#else
|
||||
DoWriteI64(buffer, size, m_output, m_be_order);
|
||||
#endif
|
||||
}
|
||||
#endif // wxHAS_INT64
|
||||
|
||||
#if defined(wxLongLong_t) && wxUSE_LONGLONG
|
||||
void wxDataOutputStream::Write64(const wxULongLong *buffer, size_t size)
|
||||
{
|
||||
DoWriteLL(buffer, size, m_output, m_be_order);
|
||||
}
|
||||
|
||||
void wxDataOutputStream::Write64(const wxLongLong *buffer, size_t size)
|
||||
{
|
||||
DoWriteLL(buffer, size, m_output, m_be_order);
|
||||
}
|
||||
#endif // wxLongLong_t
|
||||
|
||||
#if wxUSE_LONGLONG
|
||||
void wxDataOutputStream::WriteLL(const wxULongLong *buffer, size_t size)
|
||||
{
|
||||
DoWriteLL(buffer, size, m_output, m_be_order);
|
||||
}
|
||||
|
||||
void wxDataOutputStream::WriteLL(const wxLongLong *buffer, size_t size)
|
||||
{
|
||||
DoWriteLL(buffer, size, m_output, m_be_order);
|
||||
}
|
||||
|
||||
void wxDataOutputStream::WriteLL(const wxLongLong &ll)
|
||||
{
|
||||
WriteLL(&ll, 1);
|
||||
}
|
||||
|
||||
void wxDataOutputStream::WriteLL(const wxULongLong &ll)
|
||||
{
|
||||
WriteLL(&ll, 1);
|
||||
}
|
||||
#endif // wxUSE_LONGLONG
|
||||
|
||||
void wxDataOutputStream::Write32(const wxUint32 *buffer, size_t size)
|
||||
{
|
||||
if (m_be_order)
|
||||
{
|
||||
for (wxUint32 i=0; i<size ;i++)
|
||||
{
|
||||
wxUint32 i32 = wxUINT32_SWAP_ON_LE(*buffer);
|
||||
buffer++;
|
||||
m_output->Write(&i32, 4);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (wxUint32 i=0; i<size ;i++)
|
||||
{
|
||||
wxUint32 i32 = wxUINT32_SWAP_ON_BE(*buffer);
|
||||
buffer++;
|
||||
m_output->Write(&i32, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxDataOutputStream::Write16(const wxUint16 *buffer, size_t size)
|
||||
{
|
||||
if (m_be_order)
|
||||
{
|
||||
for (wxUint32 i=0; i<size ;i++)
|
||||
{
|
||||
wxUint16 i16 = wxUINT16_SWAP_ON_LE(*buffer);
|
||||
buffer++;
|
||||
m_output->Write(&i16, 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (wxUint32 i=0; i<size ;i++)
|
||||
{
|
||||
wxUint16 i16 = wxUINT16_SWAP_ON_BE(*buffer);
|
||||
buffer++;
|
||||
m_output->Write(&i16, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxDataOutputStream::Write8(const wxUint8 *buffer, size_t size)
|
||||
{
|
||||
m_output->Write(buffer, size);
|
||||
}
|
||||
|
||||
void wxDataOutputStream::WriteDouble(const double *buffer, size_t size)
|
||||
{
|
||||
for (wxUint32 i=0; i<size; i++)
|
||||
{
|
||||
WriteDouble(*(buffer++));
|
||||
}
|
||||
}
|
||||
|
||||
void wxDataOutputStream::WriteFloat(const float *buffer, size_t size)
|
||||
{
|
||||
for (wxUint32 i=0; i<size; i++)
|
||||
{
|
||||
WriteFloat(*(buffer++));
|
||||
}
|
||||
}
|
||||
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(const wxString& string)
|
||||
{
|
||||
WriteString(string);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(wxInt8 c)
|
||||
{
|
||||
Write8((wxUint8)c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(wxInt16 i)
|
||||
{
|
||||
Write16((wxUint16)i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(wxInt32 i)
|
||||
{
|
||||
Write32((wxUint32)i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(wxUint8 c)
|
||||
{
|
||||
Write8(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(wxUint16 i)
|
||||
{
|
||||
Write16(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(wxUint32 i)
|
||||
{
|
||||
Write32(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if wxHAS_INT64
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(wxUint64 i)
|
||||
{
|
||||
Write64(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(wxInt64 i)
|
||||
{
|
||||
Write64(i);
|
||||
return *this;
|
||||
}
|
||||
#endif // wxHAS_INT64
|
||||
|
||||
#if defined(wxLongLong_t) && wxUSE_LONGLONG
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(const wxULongLong &i)
|
||||
{
|
||||
WriteLL(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(const wxLongLong &i)
|
||||
{
|
||||
WriteLL(i);
|
||||
return *this;
|
||||
}
|
||||
#endif // wxLongLong_t
|
||||
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(double d)
|
||||
{
|
||||
WriteDouble(d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDataOutputStream& wxDataOutputStream::operator<<(float f)
|
||||
{
|
||||
WriteFloat(f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif
|
||||
// wxUSE_STREAMS
|
||||
@@ -0,0 +1,756 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/debugrpt.cpp
|
||||
// Purpose: wxDebugReport and related classes implementation
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 2005-01-17
|
||||
// Copyright: (c) 2005 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/app.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/utils.h"
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
WX_CHECK_BUILD_OPTIONS("wxQA")
|
||||
|
||||
#if wxUSE_DEBUGREPORT && wxUSE_XML
|
||||
|
||||
#include "wx/debugrpt.h"
|
||||
#if wxUSE_FFILE
|
||||
#include "wx/ffile.h"
|
||||
#elif wxUSE_FILE
|
||||
#include "wx/file.h"
|
||||
#endif
|
||||
|
||||
#include "wx/filename.h"
|
||||
#include "wx/dir.h"
|
||||
#include "wx/dynlib.h"
|
||||
|
||||
#include "wx/xml/xml.h"
|
||||
|
||||
#if wxUSE_STACKWALKER
|
||||
#include "wx/stackwalk.h"
|
||||
#endif
|
||||
|
||||
#if wxUSE_CRASHREPORT
|
||||
#include "wx/msw/crashrpt.h"
|
||||
#endif
|
||||
|
||||
#if wxUSE_ZIPSTREAM
|
||||
#include "wx/wfstream.h"
|
||||
#include "wx/zipstrm.h"
|
||||
#endif // wxUSE_ZIPSTREAM
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// XmlStackWalker: stack walker specialization which dumps stack in XML
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_STACKWALKER
|
||||
|
||||
class XmlStackWalker : public wxStackWalker
|
||||
{
|
||||
public:
|
||||
XmlStackWalker(wxXmlNode *nodeStack)
|
||||
{
|
||||
m_isOk = false;
|
||||
m_nodeStack = nodeStack;
|
||||
}
|
||||
|
||||
bool IsOk() const { return m_isOk; }
|
||||
|
||||
protected:
|
||||
virtual void OnStackFrame(const wxStackFrame& frame) wxOVERRIDE;
|
||||
|
||||
wxXmlNode *m_nodeStack;
|
||||
bool m_isOk;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// local functions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static inline void
|
||||
HexProperty(wxXmlNode *node, const wxChar *name, wxUIntPtr value)
|
||||
{
|
||||
node->AddAttribute(name, wxString::Format(wxT("%#zx"), value));
|
||||
}
|
||||
|
||||
static inline void
|
||||
NumProperty(wxXmlNode *node, const wxChar *name, unsigned long value)
|
||||
{
|
||||
node->AddAttribute(name, wxString::Format(wxT("%lu"), value));
|
||||
}
|
||||
|
||||
static inline void
|
||||
TextElement(wxXmlNode *node, const wxChar *name, const wxString& value)
|
||||
{
|
||||
wxXmlNode *nodeChild = new wxXmlNode(wxXML_ELEMENT_NODE, name);
|
||||
node->AddChild(nodeChild);
|
||||
nodeChild->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, value));
|
||||
}
|
||||
|
||||
#if wxUSE_CRASHREPORT && defined(__INTEL__)
|
||||
|
||||
static inline void
|
||||
HexElement(wxXmlNode *node, const wxChar *name, unsigned long value)
|
||||
{
|
||||
TextElement(node, name, wxString::Format(wxT("%08lx"), value));
|
||||
}
|
||||
|
||||
#endif // wxUSE_CRASHREPORT
|
||||
|
||||
// ============================================================================
|
||||
// XmlStackWalker implementation
|
||||
// ============================================================================
|
||||
|
||||
void XmlStackWalker::OnStackFrame(const wxStackFrame& frame)
|
||||
{
|
||||
m_isOk = true;
|
||||
|
||||
wxXmlNode *nodeFrame = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("frame"));
|
||||
m_nodeStack->AddChild(nodeFrame);
|
||||
|
||||
NumProperty(nodeFrame, wxT("level"), frame.GetLevel());
|
||||
wxString func = frame.GetName();
|
||||
if ( !func.empty() )
|
||||
nodeFrame->AddAttribute(wxT("function"), func);
|
||||
|
||||
HexProperty(nodeFrame, wxT("offset"), frame.GetOffset());
|
||||
HexProperty(nodeFrame, wxT("address"), wxPtrToUInt(frame.GetAddress()));
|
||||
|
||||
wxString module = frame.GetModule();
|
||||
if ( !module.empty() )
|
||||
nodeFrame->AddAttribute(wxT("module"), module);
|
||||
|
||||
if ( frame.HasSourceLocation() )
|
||||
{
|
||||
nodeFrame->AddAttribute(wxT("file"), frame.GetFileName());
|
||||
NumProperty(nodeFrame, wxT("line"), frame.GetLine());
|
||||
}
|
||||
|
||||
const size_t nParams = frame.GetParamCount();
|
||||
if ( nParams )
|
||||
{
|
||||
wxXmlNode *nodeParams = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("parameters"));
|
||||
nodeFrame->AddChild(nodeParams);
|
||||
|
||||
for ( size_t n = 0; n < nParams; n++ )
|
||||
{
|
||||
wxXmlNode *
|
||||
nodeParam = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("parameter"));
|
||||
nodeParams->AddChild(nodeParam);
|
||||
|
||||
NumProperty(nodeParam, wxT("number"), n);
|
||||
|
||||
wxString type, name, value;
|
||||
if ( !frame.GetParam(n, &type, &name, &value) )
|
||||
continue;
|
||||
|
||||
if ( !type.empty() )
|
||||
TextElement(nodeParam, wxT("type"), type);
|
||||
|
||||
if ( !name.empty() )
|
||||
TextElement(nodeParam, wxT("name"), name);
|
||||
|
||||
if ( !value.empty() )
|
||||
TextElement(nodeParam, wxT("value"), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_STACKWALKER
|
||||
|
||||
// ============================================================================
|
||||
// wxDebugReport implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// initialization and cleanup
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxDebugReport::wxDebugReport()
|
||||
{
|
||||
// get a temporary directory name
|
||||
wxString appname = GetReportName();
|
||||
|
||||
// we can't use CreateTempFileName() because it creates a file, not a
|
||||
// directory, so do our best to create a unique name ourselves
|
||||
//
|
||||
// of course, this doesn't protect us against malicious users...
|
||||
#if wxUSE_DATETIME
|
||||
m_dir.Printf(wxT("%s%c%s_dbgrpt-%lu-%s"),
|
||||
wxFileName::GetTempDir(), wxFILE_SEP_PATH, appname,
|
||||
wxGetProcessId(),
|
||||
wxDateTime::Now().Format(wxT("%Y%m%dT%H%M%S")));
|
||||
#else
|
||||
m_dir.Printf(wxT("%s%c%s_dbgrpt-%lu"),
|
||||
wxFileName::GetTempDir(), wxFILE_SEP_PATH, appname,
|
||||
wxGetProcessId());
|
||||
#endif
|
||||
|
||||
// as we are going to save the process state there use restrictive
|
||||
// permissions
|
||||
if ( !wxMkdir(m_dir, 0700) )
|
||||
{
|
||||
wxLogSysError(_("Failed to create directory \"%s\""), m_dir.c_str());
|
||||
wxLogError(_("Debug report couldn't be created."));
|
||||
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
wxDebugReport::~wxDebugReport()
|
||||
{
|
||||
if ( !m_dir.empty() )
|
||||
{
|
||||
// remove all files in this directory
|
||||
wxDir dir(m_dir);
|
||||
wxString file;
|
||||
for ( bool cont = dir.GetFirst(&file); cont; cont = dir.GetNext(&file) )
|
||||
{
|
||||
if ( wxRemove(wxFileName(m_dir, file).GetFullPath()) != 0 )
|
||||
{
|
||||
wxLogSysError(_("Failed to remove debug report file \"%s\""),
|
||||
file.c_str());
|
||||
m_dir.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !m_dir.empty() )
|
||||
{
|
||||
if ( wxRmDir(m_dir) != 0 )
|
||||
{
|
||||
wxLogSysError(_("Failed to clean up debug report directory \"%s\""),
|
||||
m_dir.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// various helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxString wxDebugReport::GetReportName() const
|
||||
{
|
||||
if ( wxTheApp )
|
||||
return wxTheApp->GetAppName();
|
||||
|
||||
return wxT("wx");
|
||||
}
|
||||
|
||||
void
|
||||
wxDebugReport::AddFile(const wxString& filename, const wxString& description)
|
||||
{
|
||||
wxString name;
|
||||
wxFileName fn(filename);
|
||||
if ( fn.IsAbsolute() )
|
||||
{
|
||||
// we need to copy the file to the debug report directory: give it the
|
||||
// same name there
|
||||
name = fn.GetFullName();
|
||||
|
||||
if (!wxCopyFile(fn.GetFullPath(),
|
||||
wxFileName(GetDirectory(), name).GetFullPath()))
|
||||
return;
|
||||
}
|
||||
else // file relative to the report directory
|
||||
{
|
||||
name = filename;
|
||||
|
||||
wxASSERT_MSG( wxFileName(GetDirectory(), name).FileExists(),
|
||||
wxT("file should exist in debug report directory") );
|
||||
}
|
||||
|
||||
m_files.Add(name);
|
||||
m_descriptions.Add(description);
|
||||
}
|
||||
|
||||
bool
|
||||
wxDebugReport::AddText(const wxString& filename,
|
||||
const wxString& text,
|
||||
const wxString& description)
|
||||
{
|
||||
#if wxUSE_FFILE || wxUSE_FILE
|
||||
wxASSERT_MSG( !wxFileName(filename).IsAbsolute(),
|
||||
wxT("filename should be relative to debug report directory") );
|
||||
|
||||
const wxString fullPath = wxFileName(GetDirectory(), filename).GetFullPath();
|
||||
#if wxUSE_FFILE
|
||||
wxFFile file(fullPath, wxT("w"));
|
||||
#elif wxUSE_FILE
|
||||
wxFile file(fullPath, wxFile::write);
|
||||
#endif
|
||||
if ( !file.IsOpened() || !file.Write(text, wxConvAuto()) )
|
||||
return false;
|
||||
|
||||
AddFile(filename, description);
|
||||
|
||||
return true;
|
||||
#else // !wxUSE_FFILE && !wxUSE_FILE
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void wxDebugReport::RemoveFile(const wxString& name)
|
||||
{
|
||||
const int n = m_files.Index(name);
|
||||
wxCHECK_RET( n != wxNOT_FOUND, wxT("No such file in wxDebugReport") );
|
||||
|
||||
m_files.RemoveAt(n);
|
||||
m_descriptions.RemoveAt(n);
|
||||
|
||||
wxRemove(wxFileName(GetDirectory(), name).GetFullPath());
|
||||
}
|
||||
|
||||
bool wxDebugReport::GetFile(size_t n, wxString *name, wxString *desc) const
|
||||
{
|
||||
if ( n >= m_files.GetCount() )
|
||||
return false;
|
||||
|
||||
if ( name )
|
||||
*name = m_files[n];
|
||||
if ( desc )
|
||||
*desc = m_descriptions[n];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxDebugReport::AddAll(Context context)
|
||||
{
|
||||
#if wxUSE_STACKWALKER
|
||||
AddContext(context);
|
||||
#endif // wxUSE_STACKWALKER
|
||||
|
||||
#if wxUSE_CRASHREPORT
|
||||
AddDump(context);
|
||||
#endif // wxUSE_CRASHREPORT
|
||||
|
||||
#if !wxUSE_STACKWALKER && !wxUSE_CRASHREPORT
|
||||
wxUnusedVar(context);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// adding basic text information about current context
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_STACKWALKER
|
||||
|
||||
bool wxDebugReport::DoAddSystemInfo(wxXmlNode *nodeSystemInfo)
|
||||
{
|
||||
nodeSystemInfo->AddAttribute(wxT("description"), wxGetOsDescription());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxDebugReport::DoAddLoadedModules(wxXmlNode *nodeModules)
|
||||
{
|
||||
wxDynamicLibraryDetailsArray modules(wxDynamicLibrary::ListLoaded());
|
||||
const size_t count = modules.GetCount();
|
||||
if ( !count )
|
||||
return false;
|
||||
|
||||
for ( size_t n = 0; n < count; n++ )
|
||||
{
|
||||
const wxDynamicLibraryDetails& info = modules[n];
|
||||
|
||||
wxXmlNode *nodeModule = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("module"));
|
||||
nodeModules->AddChild(nodeModule);
|
||||
|
||||
wxString path = info.GetPath();
|
||||
if ( path.empty() )
|
||||
path = info.GetName();
|
||||
if ( !path.empty() )
|
||||
nodeModule->AddAttribute(wxT("path"), path);
|
||||
|
||||
void *addr = NULL;
|
||||
size_t len = 0;
|
||||
if ( info.GetAddress(&addr, &len) )
|
||||
{
|
||||
HexProperty(nodeModule, wxT("address"), wxPtrToUInt(addr));
|
||||
HexProperty(nodeModule, wxT("size"), len);
|
||||
}
|
||||
|
||||
wxString ver = info.GetVersion();
|
||||
if ( !ver.empty() )
|
||||
{
|
||||
nodeModule->AddAttribute(wxT("version"), ver);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxDebugReport::DoAddExceptionInfo(wxXmlNode *nodeContext)
|
||||
{
|
||||
#if wxUSE_CRASHREPORT
|
||||
wxCrashContext c;
|
||||
if ( !c.code )
|
||||
return false;
|
||||
|
||||
wxXmlNode *nodeExc = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("exception"));
|
||||
nodeContext->AddChild(nodeExc);
|
||||
|
||||
HexProperty(nodeExc, wxT("code"), c.code);
|
||||
nodeExc->AddAttribute(wxT("name"), c.GetExceptionString());
|
||||
HexProperty(nodeExc, wxT("address"), wxPtrToUInt(c.addr));
|
||||
|
||||
#ifdef __INTEL__
|
||||
wxXmlNode *nodeRegs = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("registers"));
|
||||
nodeContext->AddChild(nodeRegs);
|
||||
HexElement(nodeRegs, wxT("eax"), c.regs.eax);
|
||||
HexElement(nodeRegs, wxT("ebx"), c.regs.ebx);
|
||||
HexElement(nodeRegs, wxT("ecx"), c.regs.edx);
|
||||
HexElement(nodeRegs, wxT("edx"), c.regs.edx);
|
||||
HexElement(nodeRegs, wxT("esi"), c.regs.esi);
|
||||
HexElement(nodeRegs, wxT("edi"), c.regs.edi);
|
||||
|
||||
HexElement(nodeRegs, wxT("ebp"), c.regs.ebp);
|
||||
HexElement(nodeRegs, wxT("esp"), c.regs.esp);
|
||||
HexElement(nodeRegs, wxT("eip"), c.regs.eip);
|
||||
|
||||
HexElement(nodeRegs, wxT("cs"), c.regs.cs);
|
||||
HexElement(nodeRegs, wxT("ds"), c.regs.ds);
|
||||
HexElement(nodeRegs, wxT("es"), c.regs.es);
|
||||
HexElement(nodeRegs, wxT("fs"), c.regs.fs);
|
||||
HexElement(nodeRegs, wxT("gs"), c.regs.gs);
|
||||
HexElement(nodeRegs, wxT("ss"), c.regs.ss);
|
||||
|
||||
HexElement(nodeRegs, wxT("flags"), c.regs.flags);
|
||||
#endif // __INTEL__
|
||||
|
||||
return true;
|
||||
#else // !wxUSE_CRASHREPORT
|
||||
wxUnusedVar(nodeContext);
|
||||
|
||||
return false;
|
||||
#endif // wxUSE_CRASHREPORT/!wxUSE_CRASHREPORT
|
||||
}
|
||||
|
||||
bool wxDebugReport::AddContext(wxDebugReport::Context ctx)
|
||||
{
|
||||
wxCHECK_MSG( IsOk(), false, wxT("use IsOk() first") );
|
||||
|
||||
// create XML dump of current context
|
||||
wxXmlDocument xmldoc;
|
||||
wxXmlNode *nodeRoot = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("report"));
|
||||
xmldoc.SetRoot(nodeRoot);
|
||||
nodeRoot->AddAttribute(wxT("version"), wxT("1.0"));
|
||||
nodeRoot->AddAttribute(wxT("kind"), ctx == Context_Current ? wxT("user")
|
||||
: wxT("exception"));
|
||||
|
||||
// add system information
|
||||
wxXmlNode *nodeSystemInfo = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("system"));
|
||||
if ( DoAddSystemInfo(nodeSystemInfo) )
|
||||
nodeRoot->AddChild(nodeSystemInfo);
|
||||
else
|
||||
delete nodeSystemInfo;
|
||||
|
||||
// add information about the loaded modules
|
||||
wxXmlNode *nodeModules = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("modules"));
|
||||
if ( DoAddLoadedModules(nodeModules) )
|
||||
nodeRoot->AddChild(nodeModules);
|
||||
else
|
||||
delete nodeModules;
|
||||
|
||||
// add CPU context information: this only makes sense for exceptions as our
|
||||
// current context is not very interesting otherwise
|
||||
if ( ctx == Context_Exception )
|
||||
{
|
||||
wxXmlNode *nodeContext = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("context"));
|
||||
if ( DoAddExceptionInfo(nodeContext) )
|
||||
nodeRoot->AddChild(nodeContext);
|
||||
else
|
||||
delete nodeContext;
|
||||
}
|
||||
|
||||
// add stack traceback
|
||||
#if wxUSE_STACKWALKER
|
||||
wxXmlNode *nodeStack = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("stack"));
|
||||
XmlStackWalker sw(nodeStack);
|
||||
#if wxUSE_ON_FATAL_EXCEPTION
|
||||
if ( ctx == Context_Exception )
|
||||
{
|
||||
sw.WalkFromException();
|
||||
}
|
||||
else // Context_Current
|
||||
#endif // wxUSE_ON_FATAL_EXCEPTION
|
||||
{
|
||||
sw.Walk();
|
||||
}
|
||||
|
||||
if ( sw.IsOk() )
|
||||
nodeRoot->AddChild(nodeStack);
|
||||
else
|
||||
delete nodeStack;
|
||||
#endif // wxUSE_STACKWALKER
|
||||
|
||||
// finally let the user add any extra information he needs
|
||||
DoAddCustomContext(nodeRoot);
|
||||
|
||||
|
||||
// save the entire context dump in a file
|
||||
wxFileName fn(m_dir, GetReportName(), wxT("xml"));
|
||||
|
||||
if ( !xmldoc.Save(fn.GetFullPath()) )
|
||||
return false;
|
||||
|
||||
AddFile(fn.GetFullName(), _("process context description"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // wxUSE_STACKWALKER
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// adding core dump
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_CRASHREPORT
|
||||
|
||||
bool wxDebugReport::AddDump(Context ctx)
|
||||
{
|
||||
wxCHECK_MSG( IsOk(), false, wxT("use IsOk() first") );
|
||||
|
||||
wxFileName fn(m_dir, GetReportName(), wxT("dmp"));
|
||||
wxCrashReport::SetFileName(fn.GetFullPath());
|
||||
|
||||
if ( !(ctx == Context_Exception ? wxCrashReport::Generate()
|
||||
: wxCrashReport::GenerateNow()) )
|
||||
return false;
|
||||
|
||||
AddFile(fn.GetFullName(), _("dump of the process state (binary)"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // wxUSE_CRASHREPORT
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// report processing
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxDebugReport::Process()
|
||||
{
|
||||
if ( !GetFilesCount() )
|
||||
{
|
||||
wxLogError(_("Debug report generation has failed."));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !DoProcess() )
|
||||
{
|
||||
wxLogError(_("Processing debug report has failed, leaving the files in \"%s\" directory."),
|
||||
GetDirectory().c_str());
|
||||
|
||||
Reset();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxDebugReport::DoProcess()
|
||||
{
|
||||
wxString msg(_("A debug report has been generated. It can be found in"));
|
||||
msg << wxT("\n")
|
||||
wxT("\t") << GetDirectory() << wxT("\n\n")
|
||||
<< _("And includes the following files:\n");
|
||||
|
||||
wxString name, desc;
|
||||
const size_t count = GetFilesCount();
|
||||
for ( size_t n = 0; n < count; n++ )
|
||||
{
|
||||
GetFile(n, &name, &desc);
|
||||
msg += wxString::Format("\t%s: %s\n", name, desc);
|
||||
}
|
||||
|
||||
msg += _("\nPlease send this report to the program maintainer, thank you!\n");
|
||||
|
||||
wxLogMessage(wxT("%s"), msg.c_str());
|
||||
|
||||
// we have to do this or the report would be deleted, and we don't even
|
||||
// have any way to ask the user if he wants to keep it from here
|
||||
Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
wxFileName wxDebugReport::GetSaveLocation() const
|
||||
{
|
||||
wxFileName fn;
|
||||
fn.SetPath(GetDirectory());
|
||||
return fn;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// wxDebugReport-derived classes
|
||||
// ============================================================================
|
||||
|
||||
#if wxUSE_ZIPSTREAM
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDebugReportCompress
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxDebugReportCompress::SetCompressedFileDirectory(const wxString& dir)
|
||||
{
|
||||
wxASSERT_MSG( m_zipfile.empty(), "Too late: call this before Process()" );
|
||||
|
||||
m_zipDir = dir;
|
||||
}
|
||||
|
||||
void wxDebugReportCompress::SetCompressedFileBaseName(const wxString& name)
|
||||
{
|
||||
wxASSERT_MSG( m_zipfile.empty(), "Too late: call this before Process()" );
|
||||
|
||||
m_zipName = name;
|
||||
}
|
||||
|
||||
wxFileName wxDebugReportCompress::GetSaveLocation() const
|
||||
{
|
||||
// Use the default directory as a basis for the save location, e.g.
|
||||
// %temp%/someName becomes %temp%/someName.zip.
|
||||
wxFileName fn(GetDirectory());
|
||||
if ( !m_zipDir.empty() )
|
||||
fn.SetPath(m_zipDir);
|
||||
if ( !m_zipName.empty() )
|
||||
fn.SetName(m_zipName);
|
||||
fn.SetExt("zip");
|
||||
return fn;
|
||||
}
|
||||
|
||||
bool wxDebugReportCompress::DoProcess()
|
||||
{
|
||||
#define HAS_FILE_STREAMS (wxUSE_STREAMS && (wxUSE_FILE || wxUSE_FFILE))
|
||||
#if HAS_FILE_STREAMS
|
||||
const size_t count = GetFilesCount();
|
||||
if ( !count )
|
||||
return false;
|
||||
|
||||
// create the streams
|
||||
const wxString ofullPath = GetSaveLocation().GetFullPath();
|
||||
#if wxUSE_FFILE
|
||||
wxFFileOutputStream os(ofullPath, wxT("wb"));
|
||||
#elif wxUSE_FILE
|
||||
wxFileOutputStream os(ofullPath);
|
||||
#endif
|
||||
if ( !os.IsOk() )
|
||||
return false;
|
||||
wxZipOutputStream zos(os, 9);
|
||||
|
||||
// add all files to the ZIP one
|
||||
wxString name, desc;
|
||||
for ( size_t n = 0; n < count; n++ )
|
||||
{
|
||||
GetFile(n, &name, &desc);
|
||||
|
||||
wxZipEntry *ze = new wxZipEntry(name);
|
||||
ze->SetComment(desc);
|
||||
|
||||
if ( !zos.PutNextEntry(ze) )
|
||||
return false;
|
||||
|
||||
const wxString ifullPath = wxFileName(GetDirectory(), name).GetFullPath();
|
||||
#if wxUSE_FFILE
|
||||
wxFFileInputStream is(ifullPath);
|
||||
#elif wxUSE_FILE
|
||||
wxFileInputStream is(ifullPath);
|
||||
#endif
|
||||
if ( !is.IsOk() || !zos.Write(is).IsOk() )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !zos.Close() )
|
||||
return false;
|
||||
|
||||
m_zipfile = ofullPath;
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif // HAS_FILE_STREAMS
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDebugReportUpload
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxDebugReportUpload::wxDebugReportUpload(const wxString& url,
|
||||
const wxString& input,
|
||||
const wxString& action,
|
||||
const wxString& curl)
|
||||
: m_uploadURL(url),
|
||||
m_inputField(input),
|
||||
m_curlCmd(curl)
|
||||
{
|
||||
if ( m_uploadURL.Last() != wxT('/') )
|
||||
m_uploadURL += wxT('/');
|
||||
m_uploadURL += action;
|
||||
}
|
||||
|
||||
bool wxDebugReportUpload::DoProcess()
|
||||
{
|
||||
if ( !wxDebugReportCompress::DoProcess() )
|
||||
return false;
|
||||
|
||||
|
||||
wxArrayString output, errors;
|
||||
int rc = wxExecute(wxString::Format
|
||||
(
|
||||
wxT("%s -F \"%s=@%s\" %s"),
|
||||
m_curlCmd.c_str(),
|
||||
m_inputField.c_str(),
|
||||
GetCompressedFileName().c_str(),
|
||||
m_uploadURL.c_str()
|
||||
),
|
||||
output,
|
||||
errors);
|
||||
if ( rc == -1 )
|
||||
{
|
||||
wxLogError(_("Failed to execute curl, please install it in PATH."));
|
||||
}
|
||||
else if ( rc != 0 )
|
||||
{
|
||||
const size_t count = errors.GetCount();
|
||||
if ( count )
|
||||
{
|
||||
for ( size_t n = 0; n < count; n++ )
|
||||
{
|
||||
wxLogWarning(wxT("%s"), errors[n].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
wxLogError(_("Failed to upload the debug report (error code %d)."), rc);
|
||||
}
|
||||
else // rc == 0
|
||||
{
|
||||
if ( OnServerReply(output) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // wxUSE_ZIPSTREAM
|
||||
|
||||
#endif // wxUSE_DEBUGREPORT
|
||||
@@ -0,0 +1,401 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/dircmn.cpp
|
||||
// Purpose: wxDir methods common to all implementations
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 19.05.01
|
||||
// Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/string.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/filefn.h"
|
||||
#include "wx/arrstr.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include "wx/dir.h"
|
||||
#include "wx/filename.h"
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDirTraverser
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxDirTraverseResult
|
||||
wxDirTraverser::OnOpenError(const wxString& WXUNUSED(dirname))
|
||||
{
|
||||
return wxDIR_IGNORE;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDir::HasFiles() and HasSubDirs()
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// dumb generic implementation
|
||||
|
||||
bool wxDir::HasFiles(const wxString& spec) const
|
||||
{
|
||||
wxString s;
|
||||
return GetFirst(&s, spec, wxDIR_FILES | wxDIR_HIDDEN);
|
||||
}
|
||||
|
||||
// we have a (much) faster version for Unix
|
||||
#if (defined(__CYGWIN__) && defined(__WINDOWS__)) || !defined(__UNIX_LIKE__) || defined(__WINE__)
|
||||
|
||||
bool wxDir::HasSubDirs(const wxString& spec) const
|
||||
{
|
||||
wxString s;
|
||||
return GetFirst(&s, spec, wxDIR_DIRS | wxDIR_HIDDEN);
|
||||
}
|
||||
|
||||
#endif // !Unix
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDir::GetNameWithSep()
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxString wxDir::GetNameWithSep() const
|
||||
{
|
||||
// Note that for historical reasons (i.e. because GetName() was there
|
||||
// first) we implement this one in terms of GetName() even though it might
|
||||
// actually make more sense to reverse this logic.
|
||||
|
||||
wxString name = GetName();
|
||||
if ( !name.empty() )
|
||||
{
|
||||
// Notice that even though GetName() isn't supposed to return the
|
||||
// separator, it can still be present for the root directory name.
|
||||
if ( name.Last() != wxFILE_SEP_PATH )
|
||||
name += wxFILE_SEP_PATH;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDir::Traverse()
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
size_t wxDir::Traverse(wxDirTraverser& sink,
|
||||
const wxString& filespec,
|
||||
int flags) const
|
||||
{
|
||||
wxCHECK_MSG( IsOpened(), (size_t)-1,
|
||||
wxT("dir must be opened before traversing it") );
|
||||
|
||||
// the total number of files found
|
||||
size_t nFiles = 0;
|
||||
|
||||
// the name of this dir with path delimiter at the end
|
||||
const wxString prefix = GetNameWithSep();
|
||||
|
||||
// first, recurse into subdirs
|
||||
if ( flags & wxDIR_DIRS )
|
||||
{
|
||||
wxString dirname;
|
||||
for ( bool cont = GetFirst(&dirname, wxEmptyString,
|
||||
(flags & ~(wxDIR_FILES | wxDIR_DOTDOT))
|
||||
| wxDIR_DIRS);
|
||||
cont;
|
||||
cont = cont && GetNext(&dirname) )
|
||||
{
|
||||
const wxString fulldirname = prefix + dirname;
|
||||
|
||||
switch ( sink.OnDir(fulldirname) )
|
||||
{
|
||||
default:
|
||||
wxFAIL_MSG(wxT("unexpected OnDir() return value") );
|
||||
wxFALLTHROUGH;
|
||||
|
||||
case wxDIR_STOP:
|
||||
cont = false;
|
||||
break;
|
||||
|
||||
case wxDIR_CONTINUE:
|
||||
{
|
||||
wxDir subdir;
|
||||
|
||||
// don't give the error messages for the directories
|
||||
// which we can't open: there can be all sorts of good
|
||||
// reason for this (e.g. insufficient privileges) and
|
||||
// this shouldn't be treated as an error -- instead
|
||||
// let the user code decide what to do
|
||||
bool ok;
|
||||
do
|
||||
{
|
||||
wxLogNull noLog;
|
||||
ok = subdir.Open(fulldirname);
|
||||
if ( !ok )
|
||||
{
|
||||
// ask the user code what to do
|
||||
bool tryagain;
|
||||
switch ( sink.OnOpenError(fulldirname) )
|
||||
{
|
||||
default:
|
||||
wxFAIL_MSG(wxT("unexpected OnOpenError() return value") );
|
||||
wxFALLTHROUGH;
|
||||
|
||||
case wxDIR_STOP:
|
||||
cont = false;
|
||||
wxFALLTHROUGH;
|
||||
|
||||
case wxDIR_IGNORE:
|
||||
tryagain = false;
|
||||
break;
|
||||
|
||||
case wxDIR_CONTINUE:
|
||||
tryagain = true;
|
||||
}
|
||||
|
||||
if ( !tryagain )
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ( !ok );
|
||||
|
||||
if ( ok )
|
||||
{
|
||||
nFiles += subdir.Traverse(sink, filespec, flags);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case wxDIR_IGNORE:
|
||||
// nothing to do
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now enum our own files
|
||||
if ( flags & wxDIR_FILES )
|
||||
{
|
||||
flags &= ~wxDIR_DIRS;
|
||||
|
||||
wxString filename;
|
||||
bool cont = GetFirst(&filename, filespec, flags);
|
||||
while ( cont )
|
||||
{
|
||||
wxDirTraverseResult res = sink.OnFile(prefix + filename);
|
||||
if ( res == wxDIR_STOP )
|
||||
break;
|
||||
|
||||
wxASSERT_MSG( res == wxDIR_CONTINUE,
|
||||
wxT("unexpected OnFile() return value") );
|
||||
|
||||
nFiles++;
|
||||
|
||||
cont = GetNext(&filename);
|
||||
}
|
||||
}
|
||||
|
||||
return nFiles;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDir::GetAllFiles()
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxDirTraverserSimple : public wxDirTraverser
|
||||
{
|
||||
public:
|
||||
wxDirTraverserSimple(wxArrayString& files) : m_files(files) { }
|
||||
|
||||
virtual wxDirTraverseResult OnFile(const wxString& filename) wxOVERRIDE
|
||||
{
|
||||
m_files.push_back(filename);
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) wxOVERRIDE
|
||||
{
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
private:
|
||||
wxArrayString& m_files;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxDirTraverserSimple);
|
||||
};
|
||||
|
||||
/* static */
|
||||
size_t wxDir::GetAllFiles(const wxString& dirname,
|
||||
wxArrayString *files,
|
||||
const wxString& filespec,
|
||||
int flags)
|
||||
{
|
||||
wxCHECK_MSG( files, (size_t)-1, wxT("NULL pointer in wxDir::GetAllFiles") );
|
||||
|
||||
size_t nFiles = 0;
|
||||
|
||||
wxDir dir(dirname);
|
||||
if ( dir.IsOpened() )
|
||||
{
|
||||
wxDirTraverserSimple traverser(*files);
|
||||
|
||||
nFiles += dir.Traverse(traverser, filespec, flags);
|
||||
}
|
||||
|
||||
return nFiles;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDir::FindFirst()
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxDirTraverserFindFirst : public wxDirTraverser
|
||||
{
|
||||
public:
|
||||
wxDirTraverserFindFirst() { }
|
||||
|
||||
virtual wxDirTraverseResult OnFile(const wxString& filename) wxOVERRIDE
|
||||
{
|
||||
m_file = filename;
|
||||
return wxDIR_STOP;
|
||||
}
|
||||
|
||||
virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) wxOVERRIDE
|
||||
{
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
const wxString& GetFile() const
|
||||
{
|
||||
return m_file;
|
||||
}
|
||||
|
||||
private:
|
||||
wxString m_file;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxDirTraverserFindFirst);
|
||||
};
|
||||
|
||||
/* static */
|
||||
wxString wxDir::FindFirst(const wxString& dirname,
|
||||
const wxString& filespec,
|
||||
int flags)
|
||||
{
|
||||
wxDir dir(dirname);
|
||||
if ( dir.IsOpened() )
|
||||
{
|
||||
wxDirTraverserFindFirst traverser;
|
||||
|
||||
dir.Traverse(traverser, filespec, flags | wxDIR_FILES);
|
||||
return traverser.GetFile();
|
||||
}
|
||||
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDir::GetTotalSize()
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_LONGLONG
|
||||
|
||||
class wxDirTraverserSumSize : public wxDirTraverser
|
||||
{
|
||||
public:
|
||||
wxDirTraverserSumSize() { }
|
||||
|
||||
virtual wxDirTraverseResult OnFile(const wxString& filename) wxOVERRIDE
|
||||
{
|
||||
// wxFileName::GetSize won't use this class again as
|
||||
// we're passing it a file and not a directory;
|
||||
// thus we are sure to avoid an endless loop
|
||||
wxULongLong sz = wxFileName::GetSize(filename);
|
||||
|
||||
if (sz == wxInvalidSize)
|
||||
{
|
||||
// if the GetSize() failed (this can happen because e.g. a
|
||||
// file is locked by another process), we can proceed but
|
||||
// we need to at least warn the user that the resulting
|
||||
// final size could be not reliable (if e.g. the locked
|
||||
// file is very big).
|
||||
m_skippedFiles.Add(filename);
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
m_sz += sz;
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) wxOVERRIDE
|
||||
{
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
wxULongLong GetTotalSize() const
|
||||
{ return m_sz; }
|
||||
const wxArrayString& GetSkippedFiles() const
|
||||
{ return m_skippedFiles; }
|
||||
|
||||
protected:
|
||||
wxULongLong m_sz;
|
||||
wxArrayString m_skippedFiles;
|
||||
};
|
||||
|
||||
wxULongLong wxDir::GetTotalSize(const wxString &dirname, wxArrayString *filesSkipped)
|
||||
{
|
||||
if (!wxDirExists(dirname))
|
||||
return wxInvalidSize;
|
||||
|
||||
// to get the size of this directory and its contents we need
|
||||
// to recursively walk it...
|
||||
wxDir dir(dirname);
|
||||
if ( !dir.IsOpened() )
|
||||
return wxInvalidSize;
|
||||
|
||||
wxDirTraverserSumSize traverser;
|
||||
if (dir.Traverse(traverser) == (size_t)-1 )
|
||||
return wxInvalidSize;
|
||||
|
||||
if (filesSkipped)
|
||||
*filesSkipped = traverser.GetSkippedFiles();
|
||||
|
||||
return traverser.GetTotalSize();
|
||||
}
|
||||
|
||||
#endif // wxUSE_LONGLONG
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDir helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/* static */
|
||||
bool wxDir::Exists(const wxString& dir)
|
||||
{
|
||||
return wxFileName::DirExists(dir);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool wxDir::Make(const wxString &dir, int perm, int flags)
|
||||
{
|
||||
return wxFileName::Mkdir(dir, perm, flags);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool wxDir::Remove(const wxString &dir, int flags)
|
||||
{
|
||||
return wxFileName::Rmdir(dir, flags);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/dynlib.cpp
|
||||
// Purpose: Dynamic library management
|
||||
// Author: Guilhem Lavaux
|
||||
// Modified by:
|
||||
// Created: 20/07/98
|
||||
// Copyright: (c) 1998 Guilhem Lavaux
|
||||
// 2000-2005 Vadim Zeitlin
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//FIXME: This class isn't really common at all, it should be moved into
|
||||
// platform dependent files (already done for Windows and Unix)
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_DYNLIB_CLASS
|
||||
|
||||
#include "wx/dynlib.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/intl.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/app.h"
|
||||
#include "wx/utils.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include "wx/filefn.h"
|
||||
#include "wx/filename.h" // for SplitPath()
|
||||
#include "wx/platinfo.h"
|
||||
|
||||
#include "wx/arrimpl.cpp"
|
||||
|
||||
WX_DEFINE_USER_EXPORTED_OBJARRAY(wxDynamicLibraryDetailsArray)
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// wxDynamicLibrary
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// for MSW/Unix it is defined in platform-specific file
|
||||
#if !(defined(__WINDOWS__) || defined(__UNIX__))
|
||||
|
||||
wxDllType wxDynamicLibrary::GetProgramHandle()
|
||||
{
|
||||
wxFAIL_MSG( wxT("GetProgramHandle() is not implemented under this platform"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // __WINDOWS__ || __UNIX__
|
||||
|
||||
|
||||
bool wxDynamicLibrary::Load(const wxString& libnameOrig, int flags)
|
||||
{
|
||||
wxASSERT_MSG(m_handle == 0, wxT("Library already loaded."));
|
||||
|
||||
// add the proper extension for the DLL ourselves unless told not to
|
||||
wxString libname = libnameOrig;
|
||||
if ( !(flags & wxDL_VERBATIM) )
|
||||
{
|
||||
// and also check that the libname doesn't already have it
|
||||
wxString ext;
|
||||
wxFileName::SplitPath(libname, NULL, NULL, &ext);
|
||||
if ( ext.empty() )
|
||||
{
|
||||
libname += GetDllExt(wxDL_MODULE);
|
||||
}
|
||||
}
|
||||
|
||||
m_handle = RawLoad(libname, flags);
|
||||
|
||||
if ( m_handle == 0 && !(flags & wxDL_QUIET) )
|
||||
{
|
||||
ReportError(_("Failed to load shared library '%s'"), libname);
|
||||
}
|
||||
|
||||
return IsLoaded();
|
||||
}
|
||||
|
||||
void *wxDynamicLibrary::DoGetSymbol(const wxString &name, bool *success) const
|
||||
{
|
||||
wxCHECK_MSG( IsLoaded(), NULL,
|
||||
wxT("Can't load symbol from unloaded library") );
|
||||
|
||||
void *symbol = RawGetSymbol(m_handle, name);
|
||||
|
||||
if ( success )
|
||||
*success = symbol != NULL;
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
void *wxDynamicLibrary::GetSymbol(const wxString& name, bool *success) const
|
||||
{
|
||||
void *symbol = DoGetSymbol(name, success);
|
||||
if ( !symbol )
|
||||
{
|
||||
ReportError(_("Couldn't find symbol '%s' in a dynamic library"), name);
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// informational methods
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*static*/
|
||||
wxString wxDynamicLibrary::GetDllExt(wxDynamicLibraryCategory cat)
|
||||
{
|
||||
wxUnusedVar(cat);
|
||||
#if defined(__WINDOWS__)
|
||||
return ".dll";
|
||||
#elif defined(__HPUX__)
|
||||
return ".sl";
|
||||
#elif defined(__DARWIN__)
|
||||
switch ( cat )
|
||||
{
|
||||
case wxDL_LIBRARY:
|
||||
return ".dylib";
|
||||
case wxDL_MODULE:
|
||||
return ".bundle";
|
||||
}
|
||||
wxFAIL_MSG("unreachable");
|
||||
return wxString(); // silence gcc warning
|
||||
#else
|
||||
return ".so";
|
||||
#endif
|
||||
}
|
||||
|
||||
/*static*/
|
||||
wxString
|
||||
wxDynamicLibrary::CanonicalizeName(const wxString& name,
|
||||
wxDynamicLibraryCategory cat)
|
||||
{
|
||||
wxString nameCanonic;
|
||||
|
||||
// under Unix the library names usually start with "lib" prefix, add it
|
||||
#if defined(__UNIX__)
|
||||
switch ( cat )
|
||||
{
|
||||
case wxDL_LIBRARY:
|
||||
// Library names should start with "lib" under Unix.
|
||||
nameCanonic = "lib";
|
||||
break;
|
||||
case wxDL_MODULE:
|
||||
// Module names are arbitrary and should have no prefix added.
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
nameCanonic << name << GetDllExt(cat);
|
||||
|
||||
return nameCanonic;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
wxString wxDynamicLibrary::CanonicalizePluginName(const wxString& name,
|
||||
wxPluginCategory cat)
|
||||
{
|
||||
wxString suffix;
|
||||
if ( cat == wxDL_PLUGIN_GUI )
|
||||
{
|
||||
suffix = wxPlatformInfo::Get().GetPortIdShortName();
|
||||
}
|
||||
#if wxUSE_UNICODE
|
||||
suffix << wxT('u');
|
||||
#endif
|
||||
#ifdef __WXDEBUG__
|
||||
suffix << wxT('d');
|
||||
#endif
|
||||
|
||||
if ( !suffix.empty() )
|
||||
suffix = wxString(wxT("_")) + suffix;
|
||||
|
||||
#define WXSTRINGIZE(x) #x
|
||||
#if defined(__UNIX__)
|
||||
#if (wxMINOR_VERSION % 2) == 0
|
||||
#define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y)
|
||||
#else
|
||||
#define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y) "." WXSTRINGIZE(z)
|
||||
#endif
|
||||
#else
|
||||
#if (wxMINOR_VERSION % 2) == 0
|
||||
#define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y)
|
||||
#else
|
||||
#define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y) WXSTRINGIZE(z)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
suffix << wxString::FromAscii(wxDLLVER(wxMAJOR_VERSION, wxMINOR_VERSION,
|
||||
wxRELEASE_NUMBER));
|
||||
#undef wxDLLVER
|
||||
#undef WXSTRINGIZE
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
// Add compiler identification:
|
||||
#if defined(__GNUG__)
|
||||
suffix << wxT("_gcc");
|
||||
#elif defined(__VISUALC__)
|
||||
suffix << wxT("_vc");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return CanonicalizeName(name + suffix, wxDL_MODULE);
|
||||
}
|
||||
|
||||
/*static*/
|
||||
wxString wxDynamicLibrary::GetPluginsDirectory()
|
||||
{
|
||||
#ifdef __UNIX__
|
||||
wxString format = wxGetInstallPrefix();
|
||||
if ( format.empty() )
|
||||
return wxEmptyString;
|
||||
wxString dir;
|
||||
format << wxFILE_SEP_PATH
|
||||
<< wxT("lib") << wxFILE_SEP_PATH
|
||||
<< wxT("wx") << wxFILE_SEP_PATH
|
||||
#if (wxMINOR_VERSION % 2) == 0
|
||||
<< wxT("%i.%i");
|
||||
dir.Printf(format.c_str(), wxMAJOR_VERSION, wxMINOR_VERSION);
|
||||
#else
|
||||
<< wxT("%i.%i.%i");
|
||||
dir.Printf(format.c_str(),
|
||||
wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER);
|
||||
#endif
|
||||
return dir;
|
||||
|
||||
#else // ! __UNIX__
|
||||
return wxEmptyString;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif // wxUSE_DYNLIB_CLASS
|
||||
@@ -0,0 +1,399 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/dynload.cpp
|
||||
// Purpose: Dynamic loading framework
|
||||
// Author: Ron Lee, David Falkinder, Vadim Zeitlin and a cast of 1000's
|
||||
// (derived in part from dynlib.cpp (c) 1998 Guilhem Lavaux)
|
||||
// Modified by:
|
||||
// Created: 03/12/01
|
||||
// Copyright: (c) 2001 Ron Lee <ron@debian.org>
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_DYNAMIC_LOADER
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include "wx/msw/private.h"
|
||||
#endif
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/log.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/hash.h"
|
||||
#include "wx/utils.h"
|
||||
#include "wx/module.h"
|
||||
#endif
|
||||
|
||||
#include "wx/strconv.h"
|
||||
|
||||
#include "wx/dynload.h"
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// wxPluginLibrary
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
wxDLImports* wxPluginLibrary::ms_classes = NULL;
|
||||
|
||||
class wxPluginLibraryModule : public wxModule
|
||||
{
|
||||
public:
|
||||
wxPluginLibraryModule() { }
|
||||
|
||||
// TODO: create ms_classes on demand, why always preallocate it?
|
||||
virtual bool OnInit() wxOVERRIDE
|
||||
{
|
||||
wxPluginLibrary::ms_classes = new wxDLImports;
|
||||
wxPluginManager::CreateManifest();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void OnExit() wxOVERRIDE
|
||||
{
|
||||
wxDELETE(wxPluginLibrary::ms_classes);
|
||||
wxPluginManager::ClearManifest();
|
||||
}
|
||||
|
||||
private:
|
||||
wxDECLARE_DYNAMIC_CLASS(wxPluginLibraryModule);
|
||||
};
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxPluginLibraryModule, wxModule);
|
||||
|
||||
|
||||
wxPluginLibrary::wxPluginLibrary(const wxString &libname, int flags)
|
||||
: m_linkcount(1)
|
||||
, m_objcount(0)
|
||||
{
|
||||
const wxClassInfo* const oldFirst = wxClassInfo::GetFirst();
|
||||
Load( libname, flags );
|
||||
|
||||
// It is simple to know what is the first object in the linked list of
|
||||
// wxClassInfo that we registered (it's also the last one chronologically),
|
||||
// it's just the new head of the wxClassInfo list:
|
||||
m_ourFirst = wxClassInfo::GetFirst();
|
||||
|
||||
// But to find the first wxClassInfo created by this library we need to
|
||||
// iterate until we get to the previous head as we don't have the links in
|
||||
// the backwards direction:
|
||||
if ( m_ourFirst != oldFirst )
|
||||
{
|
||||
for ( const wxClassInfo* info = m_ourFirst; ; info = info->GetNext() )
|
||||
{
|
||||
if ( info->GetNext() == oldFirst )
|
||||
{
|
||||
m_ourLast = info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // We didn't register any classes at all.
|
||||
{
|
||||
m_ourFirst =
|
||||
m_ourLast = NULL;
|
||||
}
|
||||
|
||||
if( m_handle != 0 )
|
||||
{
|
||||
UpdateClasses();
|
||||
RegisterModules();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag us for deletion
|
||||
--m_linkcount;
|
||||
}
|
||||
}
|
||||
|
||||
wxPluginLibrary::~wxPluginLibrary()
|
||||
{
|
||||
if( m_handle != 0 )
|
||||
{
|
||||
UnregisterModules();
|
||||
RestoreClasses();
|
||||
}
|
||||
}
|
||||
|
||||
wxPluginLibrary *wxPluginLibrary::RefLib()
|
||||
{
|
||||
wxCHECK_MSG( m_linkcount > 0, NULL,
|
||||
wxT("Library had been already deleted!") );
|
||||
|
||||
++m_linkcount;
|
||||
return this;
|
||||
}
|
||||
|
||||
bool wxPluginLibrary::UnrefLib()
|
||||
{
|
||||
wxASSERT_MSG( m_objcount == 0,
|
||||
wxT("Library unloaded before all objects were destroyed") );
|
||||
|
||||
if ( m_linkcount == 0 || --m_linkcount == 0 )
|
||||
{
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
// Private methods
|
||||
// ------------------------
|
||||
|
||||
void wxPluginLibrary::UpdateClasses()
|
||||
{
|
||||
if ( !m_ourFirst )
|
||||
return;
|
||||
|
||||
for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
|
||||
{
|
||||
if( info->GetClassName() )
|
||||
{
|
||||
// Hash all the class names into a local table too so
|
||||
// we can quickly find the entry they correspond to.
|
||||
(*ms_classes)[info->GetClassName()] = this;
|
||||
}
|
||||
|
||||
if ( info == m_ourLast )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void wxPluginLibrary::RestoreClasses()
|
||||
{
|
||||
// Check if there is a need to restore classes.
|
||||
if (!ms_classes)
|
||||
return;
|
||||
|
||||
if ( !m_ourFirst )
|
||||
return;
|
||||
|
||||
for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
|
||||
{
|
||||
ms_classes->erase(ms_classes->find(info->GetClassName()));
|
||||
|
||||
if ( info == m_ourLast )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void wxPluginLibrary::RegisterModules()
|
||||
{
|
||||
// Plugin libraries might have wxModules, Register and initialise them if
|
||||
// they do.
|
||||
//
|
||||
// Note that these classes are NOT included in the reference counting since
|
||||
// it's implicit that they will be unloaded if and when the last handle to
|
||||
// the library is. We do have to keep a copy of the module's pointer
|
||||
// though, as there is currently no way to Unregister it without it.
|
||||
|
||||
wxASSERT_MSG( m_linkcount == 1,
|
||||
wxT("RegisterModules should only be called for the first load") );
|
||||
|
||||
if ( m_ourFirst )
|
||||
{
|
||||
for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
|
||||
{
|
||||
if( info->IsKindOf(wxCLASSINFO(wxModule)) )
|
||||
{
|
||||
wxModule *m = wxDynamicCast(info->CreateObject(), wxModule);
|
||||
|
||||
wxASSERT_MSG( m, wxT("wxDynamicCast of wxModule failed") );
|
||||
|
||||
m_wxmodules.push_back(m);
|
||||
wxModule::RegisterModule(m);
|
||||
}
|
||||
|
||||
if ( info == m_ourLast )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Likewise this is (well was) very similar to InitializeModules()
|
||||
|
||||
for ( wxModuleList::iterator it = m_wxmodules.begin();
|
||||
it != m_wxmodules.end();
|
||||
++it)
|
||||
{
|
||||
if( !(*it)->Init() )
|
||||
{
|
||||
wxLogDebug(wxT("wxModule::Init() failed for wxPluginLibrary"));
|
||||
|
||||
// XXX: Watch this, a different hash implementation might break it,
|
||||
// a good hash implementation would let us fix it though.
|
||||
|
||||
// The name of the game is to remove any uninitialised modules and
|
||||
// let the dtor Exit the rest on shutdown, (which we'll initiate
|
||||
// shortly).
|
||||
|
||||
wxModuleList::iterator oldNode = m_wxmodules.end();
|
||||
do {
|
||||
++it;
|
||||
if( oldNode != m_wxmodules.end() )
|
||||
m_wxmodules.erase(oldNode);
|
||||
wxModule::UnregisterModule( *it );
|
||||
oldNode = it;
|
||||
} while( it != m_wxmodules.end() );
|
||||
|
||||
--m_linkcount; // Flag us for deletion
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxPluginLibrary::UnregisterModules()
|
||||
{
|
||||
wxModuleList::iterator it;
|
||||
|
||||
for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it )
|
||||
(*it)->Exit();
|
||||
|
||||
for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it )
|
||||
wxModule::UnregisterModule( *it );
|
||||
|
||||
// NB: content of the list was deleted by UnregisterModule calls above:
|
||||
m_wxmodules.clear();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// wxPluginManager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
wxDLManifest* wxPluginManager::ms_manifest = NULL;
|
||||
|
||||
// ------------------------
|
||||
// Static accessors
|
||||
// ------------------------
|
||||
|
||||
wxPluginLibrary *
|
||||
wxPluginManager::LoadLibrary(const wxString &libname, int flags)
|
||||
{
|
||||
wxString realname(libname);
|
||||
|
||||
if( !(flags & wxDL_VERBATIM) )
|
||||
realname += wxDynamicLibrary::GetDllExt(wxDL_MODULE);
|
||||
|
||||
wxPluginLibrary *entry;
|
||||
|
||||
if ( flags & wxDL_NOSHARE )
|
||||
{
|
||||
entry = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = FindByName(realname);
|
||||
}
|
||||
|
||||
if ( entry )
|
||||
{
|
||||
wxLogTrace(wxT("dll"),
|
||||
wxT("LoadLibrary(%s): already loaded."), realname.c_str());
|
||||
|
||||
entry->RefLib();
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = new wxPluginLibrary( libname, flags );
|
||||
|
||||
if ( entry->IsLoaded() )
|
||||
{
|
||||
(*ms_manifest)[realname] = entry;
|
||||
|
||||
wxLogTrace(wxT("dll"),
|
||||
wxT("LoadLibrary(%s): loaded ok."), realname.c_str());
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace(wxT("dll"),
|
||||
wxT("LoadLibrary(%s): failed to load."), realname.c_str());
|
||||
|
||||
// we have created entry just above
|
||||
if ( !entry->UnrefLib() )
|
||||
{
|
||||
// ... so UnrefLib() is supposed to delete it
|
||||
wxFAIL_MSG( wxT("Currently linked library is not loaded?") );
|
||||
}
|
||||
|
||||
entry = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool wxPluginManager::UnloadLibrary(const wxString& libname)
|
||||
{
|
||||
wxString realname = libname;
|
||||
|
||||
wxPluginLibrary *entry = FindByName(realname);
|
||||
|
||||
if ( !entry )
|
||||
{
|
||||
realname += wxDynamicLibrary::GetDllExt(wxDL_MODULE);
|
||||
|
||||
entry = FindByName(realname);
|
||||
}
|
||||
|
||||
if ( !entry )
|
||||
{
|
||||
wxLogDebug(wxT("Attempt to unload library '%s' which is not loaded."),
|
||||
libname.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxLogTrace(wxT("dll"), wxT("UnloadLibrary(%s)"), realname.c_str());
|
||||
|
||||
if ( !entry->UnrefLib() )
|
||||
{
|
||||
// not really unloaded yet
|
||||
return false;
|
||||
}
|
||||
|
||||
ms_manifest->erase(ms_manifest->find(realname));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
// Class implementation
|
||||
// ------------------------
|
||||
|
||||
bool wxPluginManager::Load(const wxString &libname, int flags)
|
||||
{
|
||||
m_entry = wxPluginManager::LoadLibrary(libname, flags);
|
||||
|
||||
return IsLoaded();
|
||||
}
|
||||
|
||||
void wxPluginManager::Unload()
|
||||
{
|
||||
wxCHECK_RET( m_entry, wxT("unloading an invalid wxPluginManager?") );
|
||||
|
||||
for ( wxDLManifest::iterator i = ms_manifest->begin();
|
||||
i != ms_manifest->end();
|
||||
++i )
|
||||
{
|
||||
if ( i->second == m_entry )
|
||||
{
|
||||
ms_manifest->erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_entry->UnrefLib();
|
||||
|
||||
m_entry = NULL;
|
||||
}
|
||||
|
||||
#endif // wxUSE_DYNAMIC_LOADER
|
||||
@@ -0,0 +1,504 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/encconv.cpp
|
||||
// Purpose: wxEncodingConverter class for converting between different
|
||||
// font encodings
|
||||
// Author: Vaclav Slavik
|
||||
// Copyright: (c) 1999 Vaclav Slavik
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/encconv.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// conversion tables, generated by scripts in $(WXWIN)/misc/unictabl:
|
||||
#if defined(__DARWIN__)
|
||||
#include "../common/unictabl.inc"
|
||||
#else
|
||||
#include "unictabl.inc"
|
||||
#endif
|
||||
|
||||
#ifdef __WXMAC__
|
||||
#include "wx/osx/core/cfstring.h"
|
||||
#include <CoreFoundation/CFString.h>
|
||||
#include <CoreFoundation/CFStringEncodingExt.h>
|
||||
|
||||
wxUint16 gMacEncodings[wxFONTENCODING_MACMAX-wxFONTENCODING_MACMIN+1][128] ;
|
||||
bool gMacEncodingsInited[wxFONTENCODING_MACMAX-wxFONTENCODING_MACMIN+1] ;
|
||||
#endif
|
||||
|
||||
static const wxUint16* GetEncTable(wxFontEncoding enc)
|
||||
{
|
||||
#ifdef __WXMAC__
|
||||
if( enc >= wxFONTENCODING_MACMIN && enc <= wxFONTENCODING_MACMAX )
|
||||
{
|
||||
int i = enc-wxFONTENCODING_MACMIN ;
|
||||
if ( gMacEncodingsInited[i] == false )
|
||||
{
|
||||
// create
|
||||
CFStringEncoding cfencoding = wxMacGetSystemEncFromFontEnc( enc ) ;
|
||||
if( !CFStringIsEncodingAvailable( cfencoding ) )
|
||||
return NULL;
|
||||
|
||||
memset( gMacEncodings[i] , 0 , 128 * 2 );
|
||||
char s[2] = { 0 , 0 };
|
||||
CFRange firstchar = CFRangeMake( 0, 1 );
|
||||
for( unsigned char c = 255 ; c >= 128 ; --c )
|
||||
{
|
||||
s[0] = c ;
|
||||
wxCFStringRef cfref( CFStringCreateWithCStringNoCopy( NULL, s, cfencoding , kCFAllocatorNull ) );
|
||||
CFStringGetCharacters( cfref, firstchar, (UniChar*) &gMacEncodings[i][c-128] );
|
||||
}
|
||||
gMacEncodingsInited[i]=true;
|
||||
}
|
||||
return gMacEncodings[i] ;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; encodings_list[i].table != NULL; i++)
|
||||
{
|
||||
if (encodings_list[i].encoding == enc)
|
||||
return encodings_list[i].table;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
wxUint16 u;
|
||||
wxUint8 c;
|
||||
} CharsetItem;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static int wxCMPFUNC_CONV
|
||||
CompareCharsetItems(const void *i1, const void *i2)
|
||||
{
|
||||
return static_cast<const CharsetItem*>(i1)->u - static_cast<const CharsetItem*>(i2)->u;
|
||||
}
|
||||
}
|
||||
|
||||
static CharsetItem* BuildReverseTable(const wxUint16 *tbl)
|
||||
{
|
||||
CharsetItem *rev = new CharsetItem[128];
|
||||
|
||||
for (int i = 0; i < 128; i++)
|
||||
rev[i].c = wxUint8(128 + i), rev[i].u = tbl[i];
|
||||
|
||||
qsort(rev, 128, sizeof(CharsetItem), CompareCharsetItems);
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
|
||||
|
||||
wxEncodingConverter::wxEncodingConverter()
|
||||
{
|
||||
m_Table = NULL;
|
||||
m_UnicodeInput = m_UnicodeOutput = false;
|
||||
m_JustCopy = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool wxEncodingConverter::Init(wxFontEncoding input_enc, wxFontEncoding output_enc, int method)
|
||||
{
|
||||
unsigned i;
|
||||
const wxUint16 *in_tbl;
|
||||
const wxUint16 *out_tbl = NULL;
|
||||
|
||||
wxDELETEA(m_Table);
|
||||
|
||||
if (input_enc == output_enc) {m_JustCopy = true; return true;}
|
||||
|
||||
m_UnicodeOutput = (output_enc == wxFONTENCODING_UNICODE);
|
||||
m_JustCopy = false;
|
||||
|
||||
if (input_enc == wxFONTENCODING_UNICODE)
|
||||
{
|
||||
if ((out_tbl = GetEncTable(output_enc)) == NULL) return false;
|
||||
|
||||
m_Table = new wchar_t[65536];
|
||||
for (i = 0; i < 128; i++) m_Table[i] = (wchar_t)i; // 7bit ASCII
|
||||
for (i = 128; i < 65536; i++) m_Table[i] = (wchar_t)0;
|
||||
|
||||
if (method == wxCONVERT_SUBSTITUTE)
|
||||
{
|
||||
for (i = 0; i < encoding_unicode_fallback_count; i++)
|
||||
m_Table[encoding_unicode_fallback[i].c] = (wchar_t) encoding_unicode_fallback[i].s;
|
||||
}
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
m_Table[out_tbl[i]] = (wchar_t)(128 + i);
|
||||
|
||||
m_UnicodeInput = true;
|
||||
}
|
||||
else // input !Unicode
|
||||
{
|
||||
if ((in_tbl = GetEncTable(input_enc)) == NULL) return false;
|
||||
if (output_enc != wxFONTENCODING_UNICODE)
|
||||
if ((out_tbl = GetEncTable(output_enc)) == NULL) return false;
|
||||
|
||||
m_UnicodeInput = false;
|
||||
|
||||
m_Table = new wchar_t[256];
|
||||
for (i = 0; i < 128; i++) m_Table[i] = (wchar_t)i; // 7bit ASCII
|
||||
|
||||
if (output_enc == wxFONTENCODING_UNICODE)
|
||||
{
|
||||
for (i = 0; i < 128; i++) m_Table[128 + i] = (wchar_t)in_tbl[i];
|
||||
return true;
|
||||
}
|
||||
else // output !Unicode
|
||||
{
|
||||
CharsetItem *rev = BuildReverseTable(out_tbl);
|
||||
CharsetItem key;
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
key.u = in_tbl[i];
|
||||
CharsetItem* item;
|
||||
item = (CharsetItem*) bsearch(&key, rev, 128, sizeof(CharsetItem), CompareCharsetItems);
|
||||
if (item == NULL && method == wxCONVERT_SUBSTITUTE)
|
||||
item = (CharsetItem*) bsearch(&key, encoding_unicode_fallback,
|
||||
encoding_unicode_fallback_count, sizeof(CharsetItem), CompareCharsetItems);
|
||||
if (item)
|
||||
m_Table[128 + i] = (wchar_t)item -> c;
|
||||
else
|
||||
m_Table[128 + i] = (wchar_t)(128 + i);
|
||||
}
|
||||
|
||||
delete[] rev;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#define REPLACEMENT_CHAR (L'?')
|
||||
|
||||
inline wchar_t GetTableValue(const wchar_t *table, wchar_t value, bool& repl)
|
||||
{
|
||||
wchar_t r = table[value];
|
||||
if (r == 0 && value != 0)
|
||||
{
|
||||
r = REPLACEMENT_CHAR;
|
||||
repl = true;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
bool wxEncodingConverter::Convert(const char* input, char* output) const
|
||||
{
|
||||
wxASSERT_MSG(!m_UnicodeOutput, wxT("You cannot convert to unicode if output is const char*!"));
|
||||
wxASSERT_MSG(!m_UnicodeInput, wxT("You cannot convert from unicode if input is const char*!"));
|
||||
|
||||
const char *i;
|
||||
char *o;
|
||||
|
||||
if (m_JustCopy)
|
||||
{
|
||||
strcpy(output, input);
|
||||
return true;
|
||||
}
|
||||
|
||||
wxCHECK_MSG(m_Table != NULL, false,
|
||||
wxT("You must call wxEncodingConverter::Init() before actually converting!"));
|
||||
|
||||
bool replaced = false;
|
||||
|
||||
for (i = input, o = output; *i != 0;)
|
||||
*(o++) = (char)(GetTableValue(m_Table, (wxUint8)*(i++), replaced));
|
||||
*o = 0;
|
||||
|
||||
return !replaced;
|
||||
}
|
||||
|
||||
|
||||
bool wxEncodingConverter::Convert(const char* input, wchar_t* output) const
|
||||
{
|
||||
wxASSERT_MSG(m_UnicodeOutput, wxT("You cannot convert to 8-bit if output is const wchar_t*!"));
|
||||
wxASSERT_MSG(!m_UnicodeInput, wxT("You cannot convert from unicode if input is const char*!"));
|
||||
|
||||
const char *i;
|
||||
wchar_t *o;
|
||||
|
||||
if (m_JustCopy)
|
||||
{
|
||||
for (i = input, o = output; *i != 0;)
|
||||
*(o++) = (wchar_t)(*(i++));
|
||||
*o = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
wxCHECK_MSG(m_Table != NULL, false,
|
||||
wxT("You must call wxEncodingConverter::Init() before actually converting!"));
|
||||
|
||||
bool replaced = false;
|
||||
|
||||
for (i = input, o = output; *i != 0;)
|
||||
*(o++) = (wchar_t)(GetTableValue(m_Table, (wxUint8)*(i++), replaced));
|
||||
*o = 0;
|
||||
|
||||
return !replaced;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool wxEncodingConverter::Convert(const wchar_t* input, char* output) const
|
||||
{
|
||||
wxASSERT_MSG(!m_UnicodeOutput, wxT("You cannot convert to unicode if output is const char*!"));
|
||||
wxASSERT_MSG(m_UnicodeInput, wxT("You cannot convert from 8-bit if input is const wchar_t*!"));
|
||||
|
||||
const wchar_t *i;
|
||||
char *o;
|
||||
|
||||
if (m_JustCopy)
|
||||
{
|
||||
for (i = input, o = output; *i != 0;)
|
||||
*(o++) = (char)(*(i++));
|
||||
*o = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
wxCHECK_MSG(m_Table != NULL, false,
|
||||
wxT("You must call wxEncodingConverter::Init() before actually converting!"));
|
||||
|
||||
bool replaced = false;
|
||||
|
||||
for (i = input, o = output; *i != 0;)
|
||||
*(o++) = (char)(GetTableValue(m_Table, (wxUint16)*(i++), replaced));
|
||||
*o = 0;
|
||||
|
||||
return !replaced;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool wxEncodingConverter::Convert(const wchar_t* input, wchar_t* output) const
|
||||
{
|
||||
wxASSERT_MSG(m_UnicodeOutput, wxT("You cannot convert to 8-bit if output is const wchar_t*!"));
|
||||
wxASSERT_MSG(m_UnicodeInput, wxT("You cannot convert from 8-bit if input is const wchar_t*!"));
|
||||
|
||||
const wchar_t *i;
|
||||
wchar_t *o;
|
||||
|
||||
if (m_JustCopy)
|
||||
{
|
||||
// wcscpy() is not guaranteed to exist
|
||||
for (i = input, o = output; *i != 0;)
|
||||
*(o++) = (*(i++));
|
||||
*o = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
wxCHECK_MSG(m_Table != NULL, false,
|
||||
wxT("You must call wxEncodingConverter::Init() before actually converting!"));
|
||||
|
||||
bool replaced = false;
|
||||
|
||||
for (i = input, o = output; *i != 0;)
|
||||
*(o++) = (wchar_t)(GetTableValue(m_Table, (wxUint8)*(i++), replaced));
|
||||
*o = 0;
|
||||
|
||||
return !replaced;
|
||||
}
|
||||
|
||||
|
||||
wxString wxEncodingConverter::Convert(const wxString& input) const
|
||||
{
|
||||
if (m_JustCopy) return input;
|
||||
|
||||
wxString s;
|
||||
const wxChar *i;
|
||||
|
||||
wxCHECK_MSG(m_Table != NULL, s,
|
||||
wxT("You must call wxEncodingConverter::Init() before actually converting!"));
|
||||
|
||||
if (m_UnicodeInput)
|
||||
{
|
||||
for (i = input.c_str(); *i != 0; i++)
|
||||
s << (wxChar)(m_Table[(wxUint16)*i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = input.c_str(); *i != 0; i++)
|
||||
s << (wxChar)(m_Table[(wxUint8)*i]);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Following tables describe classes of encoding equivalence.
|
||||
//
|
||||
|
||||
#define STOP wxFONTENCODING_SYSTEM
|
||||
|
||||
#define NUM_OF_PLATFORMS 3 /*must conform to enum wxPLATFORM_XXXX !!!*/
|
||||
#define ENC_PER_PLATFORM 3
|
||||
// max no. of encodings for one language used on one platform.
|
||||
// Using maximum of everything at the current moment to not make the
|
||||
// library larger than necessary. Make larger only if necessary - MR
|
||||
|
||||
static const wxFontEncoding
|
||||
EquivalentEncodings[][NUM_OF_PLATFORMS][ENC_PER_PLATFORM+1] = {
|
||||
|
||||
// *** Please put more common encodings as first! ***
|
||||
|
||||
// Western European
|
||||
{
|
||||
/* unix */ {wxFONTENCODING_ISO8859_1, wxFONTENCODING_ISO8859_15, STOP},
|
||||
/* windows */ {wxFONTENCODING_CP1252, STOP},
|
||||
/* mac */ {wxFONTENCODING_MACROMAN, STOP}
|
||||
},
|
||||
|
||||
// Central European
|
||||
{
|
||||
/* unix */ {wxFONTENCODING_ISO8859_2, STOP},
|
||||
/* windows */ {wxFONTENCODING_CP1250, STOP},
|
||||
/* mac */ {wxFONTENCODING_MACCENTRALEUR, STOP}
|
||||
},
|
||||
|
||||
// Baltic
|
||||
{
|
||||
/* unix */ {wxFONTENCODING_ISO8859_13, wxFONTENCODING_ISO8859_4, STOP},
|
||||
/* windows */ {wxFONTENCODING_CP1257, STOP},
|
||||
/* mac */ {STOP}
|
||||
},
|
||||
|
||||
// Hebrew
|
||||
{
|
||||
/* unix */ {wxFONTENCODING_ISO8859_8, STOP},
|
||||
/* windows */ {wxFONTENCODING_CP1255, STOP},
|
||||
/* mac */ {wxFONTENCODING_MACHEBREW, STOP}
|
||||
},
|
||||
|
||||
// Greek
|
||||
{
|
||||
/* unix */ {wxFONTENCODING_ISO8859_7, STOP},
|
||||
/* windows */ {wxFONTENCODING_CP1253, STOP},
|
||||
/* mac */ {wxFONTENCODING_MACGREEK, STOP}
|
||||
},
|
||||
|
||||
// Arabic
|
||||
{
|
||||
/* unix */ {wxFONTENCODING_ISO8859_6, STOP},
|
||||
/* windows */ {wxFONTENCODING_CP1256, STOP},
|
||||
/* mac */ {wxFONTENCODING_MACARABIC, STOP}
|
||||
},
|
||||
|
||||
// Turkish
|
||||
{
|
||||
/* unix */ {wxFONTENCODING_ISO8859_9, STOP},
|
||||
/* windows */ {wxFONTENCODING_CP1254, STOP},
|
||||
/* mac */ {wxFONTENCODING_MACTURKISH, STOP}
|
||||
},
|
||||
|
||||
// Cyrillic
|
||||
{
|
||||
/* unix */ {wxFONTENCODING_KOI8, wxFONTENCODING_KOI8_U, wxFONTENCODING_ISO8859_5, STOP},
|
||||
/* windows */ {wxFONTENCODING_CP1251, STOP},
|
||||
/* mac */ {wxFONTENCODING_MACCYRILLIC, STOP}
|
||||
},
|
||||
|
||||
{{STOP},{STOP},{STOP}} /* Terminator */
|
||||
/* no, _not_ Arnold! */
|
||||
};
|
||||
|
||||
|
||||
static bool FindEncoding(const wxFontEncodingArray& arr, wxFontEncoding f)
|
||||
{
|
||||
for (wxFontEncodingArray::const_iterator it = arr.begin(), en = arr.end();
|
||||
it != en; ++it)
|
||||
if (*it == f)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
wxFontEncodingArray wxEncodingConverter::GetPlatformEquivalents(wxFontEncoding enc, int platform)
|
||||
{
|
||||
if (platform == wxPLATFORM_CURRENT)
|
||||
{
|
||||
#if defined(__WINDOWS__)
|
||||
platform = wxPLATFORM_WINDOWS;
|
||||
#elif defined(__WXMAC__)
|
||||
platform = wxPLATFORM_MAC;
|
||||
#else
|
||||
platform = wxPLATFORM_UNIX;
|
||||
#endif
|
||||
}
|
||||
|
||||
switch ( platform )
|
||||
{
|
||||
case wxPLATFORM_UNIX:
|
||||
case wxPLATFORM_WINDOWS:
|
||||
case wxPLATFORM_MAC:
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG(wxS("Invalid platform specified"));
|
||||
return wxFontEncodingArray();
|
||||
}
|
||||
|
||||
int i, clas, e ;
|
||||
const wxFontEncoding *f;
|
||||
wxFontEncodingArray arr;
|
||||
|
||||
clas = 0;
|
||||
while (EquivalentEncodings[clas][0][0] != STOP)
|
||||
{
|
||||
for (i = 0; i < NUM_OF_PLATFORMS; i++)
|
||||
for (e = 0; EquivalentEncodings[clas][i][e] != STOP; e++)
|
||||
if (EquivalentEncodings[clas][i][e] == enc)
|
||||
{
|
||||
for (f = EquivalentEncodings[clas][platform]; *f != STOP; f++)
|
||||
if (*f == enc) arr.push_back(enc);
|
||||
for (f = EquivalentEncodings[clas][platform]; *f != STOP; f++)
|
||||
if (!FindEncoding(arr, *f)) arr.push_back(*f);
|
||||
i = NUM_OF_PLATFORMS/*hack*/; break;
|
||||
}
|
||||
clas++;
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
wxFontEncodingArray wxEncodingConverter::GetAllEquivalents(wxFontEncoding enc)
|
||||
{
|
||||
int i, clas, e, j ;
|
||||
const wxFontEncoding *f;
|
||||
wxFontEncodingArray arr;
|
||||
|
||||
arr = GetPlatformEquivalents(enc); // we want them to be first items in array
|
||||
|
||||
clas = 0;
|
||||
while (EquivalentEncodings[clas][0][0] != STOP)
|
||||
{
|
||||
for (i = 0; i < NUM_OF_PLATFORMS; i++)
|
||||
for (e = 0; EquivalentEncodings[clas][i][e] != STOP; e++)
|
||||
if (EquivalentEncodings[clas][i][e] == enc)
|
||||
{
|
||||
for (j = 0; j < NUM_OF_PLATFORMS; j++)
|
||||
for (f = EquivalentEncodings[clas][j]; *f != STOP; f++)
|
||||
if (!FindEncoding(arr, *f)) arr.push_back(*f);
|
||||
i = NUM_OF_PLATFORMS/*hack*/; break;
|
||||
}
|
||||
clas++;
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,397 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/evtloopcmn.cpp
|
||||
// Purpose: common wxEventLoop-related stuff
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2006-01-12
|
||||
// Copyright: (c) 2006, 2013 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// (c) 2013 Rob Bresalier
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/evtloop.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/app.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include "wx/scopeguard.h"
|
||||
#include "wx/apptrait.h"
|
||||
#include "wx/private/eventloopsourcesmanager.h"
|
||||
|
||||
// Counts currently existing event loops.
|
||||
//
|
||||
// As wxEventLoop can be only used from the main thread, there is no need to
|
||||
// protect accesses to this variable.
|
||||
static int gs_eventLoopCount = 0;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxEventLoopBase
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxEventLoopBase *wxEventLoopBase::ms_activeLoop = NULL;
|
||||
|
||||
wxEventLoopBase::wxEventLoopBase()
|
||||
{
|
||||
gs_eventLoopCount++;
|
||||
|
||||
m_isInsideRun = false;
|
||||
m_shouldExit = false;
|
||||
m_yieldLevel = 0;
|
||||
m_eventsToProcessInsideYield = wxEVT_CATEGORY_ALL;
|
||||
}
|
||||
|
||||
wxEventLoopBase::~wxEventLoopBase()
|
||||
{
|
||||
gs_eventLoopCount--;
|
||||
}
|
||||
|
||||
bool wxEventLoopBase::IsMain() const
|
||||
{
|
||||
if (wxTheApp)
|
||||
return wxTheApp->GetMainLoop() == this;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void wxEventLoopBase::SetActive(wxEventLoopBase* loop)
|
||||
{
|
||||
ms_activeLoop = loop;
|
||||
|
||||
if (wxTheApp)
|
||||
wxTheApp->OnEventLoopEnter(loop);
|
||||
}
|
||||
|
||||
int wxEventLoopBase::Run()
|
||||
{
|
||||
// event loops are not recursive, you need to create another loop!
|
||||
wxCHECK_MSG( !IsInsideRun(), -1, wxT("can't reenter a message loop") );
|
||||
|
||||
// ProcessIdle() and ProcessEvents() below may throw so the code here should
|
||||
// be exception-safe, hence we must use local objects for all actions we
|
||||
// should undo
|
||||
wxEventLoopActivator activate(this);
|
||||
|
||||
// We might be called again, after a previous call to ScheduleExit(), so
|
||||
// reset this flag.
|
||||
m_shouldExit = false;
|
||||
|
||||
// Set this variable to true for the duration of this method.
|
||||
m_isInsideRun = true;
|
||||
wxON_BLOCK_EXIT_SET(m_isInsideRun, false);
|
||||
|
||||
// Finally really run the loop.
|
||||
return DoRun();
|
||||
}
|
||||
|
||||
void wxEventLoopBase::Exit(int rc)
|
||||
{
|
||||
wxCHECK_RET( IsRunning(), wxS("Use ScheduleExit() on not running loop") );
|
||||
|
||||
ScheduleExit(rc);
|
||||
}
|
||||
void wxEventLoopBase::OnExit()
|
||||
{
|
||||
if (wxTheApp)
|
||||
wxTheApp->OnEventLoopExit(this);
|
||||
}
|
||||
|
||||
bool wxEventLoopBase::ProcessIdle()
|
||||
{
|
||||
return wxTheApp && wxTheApp->ProcessIdle();
|
||||
}
|
||||
|
||||
bool wxEventLoopBase::Yield(bool onlyIfNeeded)
|
||||
{
|
||||
if ( onlyIfNeeded && IsYielding() )
|
||||
return false;
|
||||
|
||||
return YieldFor(wxEVT_CATEGORY_ALL);
|
||||
}
|
||||
|
||||
bool wxEventLoopBase::YieldFor(long eventsToProcess)
|
||||
{
|
||||
#if wxUSE_THREADS
|
||||
if ( !wxThread::IsMain() )
|
||||
{
|
||||
// Don't ever dispatch events from non-main threads.
|
||||
return false;
|
||||
}
|
||||
#endif // wxUSE_THREADS
|
||||
|
||||
// set the flag and don't forget to reset it before returning
|
||||
const int yieldLevelOld = m_yieldLevel;
|
||||
const long eventsToProcessOld = m_eventsToProcessInsideYield;
|
||||
|
||||
m_yieldLevel++;
|
||||
wxON_BLOCK_EXIT_SET(m_yieldLevel, yieldLevelOld);
|
||||
|
||||
m_eventsToProcessInsideYield = eventsToProcess;
|
||||
wxON_BLOCK_EXIT_SET(m_eventsToProcessInsideYield, eventsToProcessOld);
|
||||
|
||||
#if wxUSE_LOG
|
||||
// disable log flushing from here because a call to wxYield() shouldn't
|
||||
// normally result in message boxes popping up &c
|
||||
wxLog::Suspend();
|
||||
|
||||
// ensure the logs will be flashed again when we exit
|
||||
wxON_BLOCK_EXIT0(wxLog::Resume);
|
||||
#endif
|
||||
|
||||
DoYieldFor(eventsToProcess);
|
||||
|
||||
#if wxUSE_EXCEPTIONS
|
||||
// If any handlers called from inside DoYieldFor() threw exceptions, they
|
||||
// may have been stored for later rethrow as it's unsafe to let them escape
|
||||
// from inside DoYieldFor() itself, as it calls native functions through
|
||||
// which the exceptions can't propagate. But now that we're back to our own
|
||||
// code, we may rethrow them.
|
||||
if ( wxTheApp )
|
||||
wxTheApp->RethrowStoredException();
|
||||
#endif // wxUSE_EXCEPTIONS
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxEventLoopBase::DoYieldFor(long eventsToProcess)
|
||||
{
|
||||
// Normally yielding dispatches not only the pending native events, but
|
||||
// also the events pending in wxWidgets itself and idle events.
|
||||
//
|
||||
// Notice however that we must not do it if we're asked to process only the
|
||||
// events of specific kind, as pending events could be of any kind at all
|
||||
// (ideal would be to have a filtering version of ProcessPendingEvents()
|
||||
// too but we don't have this right now) and idle events are typically
|
||||
// unexpected when yielding for the specific event kinds only.
|
||||
if ( eventsToProcess == wxEVT_CATEGORY_ALL )
|
||||
{
|
||||
if ( wxTheApp )
|
||||
wxTheApp->ProcessPendingEvents();
|
||||
|
||||
// We call it just once, even if it returns true, because we don't want
|
||||
// to get stuck inside wxYield() forever if the application does some
|
||||
// constant background processing in its idle handler, we do need to
|
||||
// get back to the main loop soon.
|
||||
ProcessIdle();
|
||||
}
|
||||
}
|
||||
|
||||
#if wxUSE_EVENTLOOP_SOURCE
|
||||
|
||||
wxEventLoopSource*
|
||||
wxEventLoopBase::AddSourceForFD(int fd,
|
||||
wxEventLoopSourceHandler *handler,
|
||||
int flags)
|
||||
{
|
||||
#if wxUSE_CONSOLE_EVENTLOOP
|
||||
// Delegate to the event loop sources manager defined by it.
|
||||
wxEventLoopSourcesManagerBase* const
|
||||
manager = wxApp::GetValidTraits().GetEventLoopSourcesManager();
|
||||
wxCHECK_MSG( manager, NULL, wxS("Must have wxEventLoopSourcesManager") );
|
||||
|
||||
return manager->AddSourceForFD(fd, handler, flags);
|
||||
#else // !wxUSE_CONSOLE_EVENTLOOP
|
||||
return NULL;
|
||||
#endif // wxUSE_CONSOLE_EVENTLOOP/!wxUSE_CONSOLE_EVENTLOOP
|
||||
}
|
||||
|
||||
#endif // wxUSE_EVENTLOOP_SOURCE
|
||||
// wxEventLoopManual is unused in the other ports
|
||||
#if defined(__WINDOWS__) || defined(__WXDFB__) || ( ( defined(__UNIX__) && !defined(__WXOSX__) ) && wxUSE_BASE)
|
||||
|
||||
// ============================================================================
|
||||
// wxEventLoopManual implementation
|
||||
// ============================================================================
|
||||
|
||||
wxEventLoopManual::wxEventLoopManual()
|
||||
{
|
||||
m_exitcode = 0;
|
||||
}
|
||||
|
||||
bool wxEventLoopManual::ProcessEvents()
|
||||
{
|
||||
// process pending wx events first as they correspond to low-level events
|
||||
// which happened before, i.e. typically pending events were queued by a
|
||||
// previous call to Dispatch() and if we didn't process them now the next
|
||||
// call to it might enqueue them again (as happens with e.g. socket events
|
||||
// which would be generated as long as there is input available on socket
|
||||
// and this input is only removed from it when pending event handlers are
|
||||
// executed)
|
||||
if ( wxTheApp )
|
||||
{
|
||||
wxTheApp->ProcessPendingEvents();
|
||||
|
||||
// One of the pending event handlers could have decided to exit the
|
||||
// loop so check for the flag before trying to dispatch more events
|
||||
// (which could block indefinitely if no more are coming).
|
||||
if ( m_shouldExit )
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool res = Dispatch();
|
||||
|
||||
#if wxUSE_EXCEPTIONS
|
||||
// Rethrow any exceptions which could have been produced by the handlers
|
||||
// ran by Dispatch().
|
||||
if ( wxTheApp )
|
||||
wxTheApp->RethrowStoredException();
|
||||
#endif // wxUSE_EXCEPTIONS
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int wxEventLoopManual::DoRun()
|
||||
{
|
||||
|
||||
// we must ensure that OnExit() is called even if an exception is thrown
|
||||
// from inside ProcessEvents() but we must call it from Exit() in normal
|
||||
// situations because it is supposed to be called synchronously,
|
||||
// wxModalEventLoop depends on this (so we can't just use ON_BLOCK_EXIT or
|
||||
// something similar here)
|
||||
#if wxUSE_EXCEPTIONS
|
||||
for ( ;; )
|
||||
{
|
||||
try
|
||||
{
|
||||
#endif // wxUSE_EXCEPTIONS
|
||||
|
||||
// this is the event loop itself
|
||||
for ( ;; )
|
||||
{
|
||||
// give them the possibility to do whatever they want
|
||||
OnNextIteration();
|
||||
|
||||
// generate and process idle events for as long as we don't
|
||||
// have anything else to do, but stop doing this if Exit() is
|
||||
// called by one of the idle handlers
|
||||
//
|
||||
// note that Pending() only checks for pending events from the
|
||||
// underlying toolkit, but not our own pending events added by
|
||||
// QueueEvent(), so we need to call HasPendingEvents() to check
|
||||
// for them too
|
||||
while ( !m_shouldExit
|
||||
&& !Pending()
|
||||
&& !(wxTheApp && wxTheApp->HasPendingEvents())
|
||||
&& ProcessIdle() )
|
||||
;
|
||||
|
||||
// if Exit() was called, don't dispatch any more events here
|
||||
if ( m_shouldExit )
|
||||
break;
|
||||
|
||||
// a message came or no more idle processing to do, dispatch
|
||||
// all the pending events and call Dispatch() to wait for the
|
||||
// next message
|
||||
if ( !ProcessEvents() || m_shouldExit )
|
||||
break;
|
||||
}
|
||||
|
||||
// Process any still pending events.
|
||||
for ( ;; )
|
||||
{
|
||||
bool hasMoreEvents = false;
|
||||
|
||||
// We always dispatch events pending at wx level: it may be
|
||||
// important to do it before the loop exits and e.g. the modal
|
||||
// dialog possibly referenced by these events handlers is
|
||||
// destroyed. It also shouldn't result in the problems
|
||||
// described below for the native events and while there is
|
||||
// still a risk of never existing the loop due to an endless
|
||||
// stream of events generated from the user-defined event
|
||||
// handlers, we consider that well-behaved programs shouldn't
|
||||
// do this -- and if they do, it's better to keep running the
|
||||
// loop than crashing after leaving it.
|
||||
if ( wxTheApp && wxTheApp->HasPendingEvents() )
|
||||
{
|
||||
wxTheApp->ProcessPendingEvents();
|
||||
hasMoreEvents = true;
|
||||
}
|
||||
|
||||
// For the underlying toolkit events, we only handle them when
|
||||
// exiting the outermost event loop but not when exiting nested
|
||||
// loops. This is required at least under MSW where, in case of
|
||||
// a nested modal event loop, the modality has already been
|
||||
// undone as Exit() had been already called, so all UI elements
|
||||
// are re-enabled and if we dispatched events from them here,
|
||||
// we could end up reentering the same event handler that had
|
||||
// shown the modal dialog in the first place and showing the
|
||||
// dialog second time before its first instance was destroyed,
|
||||
// resulting in a lot of fun.
|
||||
//
|
||||
// Also, unlike wx events above, it should be fine to dispatch
|
||||
// the native events from the outer event loop, as any events
|
||||
// generated from outside the dialog itself (necessarily, as
|
||||
// the dialog is already hidden and about to be destroyed)
|
||||
// shouldn't reference the dialog. Which is one of the reasons
|
||||
// we still dispatch them in the outermost event loop, to
|
||||
// ensure they're still processed. Another reason is that if we
|
||||
// do have an endless stream of native events, e.g. because we
|
||||
// have a timer with a too short interval, it's arguably better
|
||||
// to keep handling them instead of exiting.
|
||||
if ( gs_eventLoopCount == 1 )
|
||||
{
|
||||
if ( Pending() )
|
||||
{
|
||||
Dispatch();
|
||||
hasMoreEvents = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !hasMoreEvents )
|
||||
break;
|
||||
}
|
||||
#if wxUSE_EXCEPTIONS
|
||||
// exit the outer loop as well
|
||||
break;
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( !wxTheApp || !wxTheApp->OnExceptionInMainLoop() )
|
||||
{
|
||||
OnExit();
|
||||
break;
|
||||
}
|
||||
//else: continue running the event loop
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
// OnException() throwed, possibly rethrowing the same
|
||||
// exception again: very good, but we still need OnExit() to
|
||||
// be called
|
||||
OnExit();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // wxUSE_EXCEPTIONS
|
||||
|
||||
return m_exitcode;
|
||||
}
|
||||
|
||||
void wxEventLoopManual::ScheduleExit(int rc)
|
||||
{
|
||||
wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not running") );
|
||||
|
||||
m_exitcode = rc;
|
||||
m_shouldExit = true;
|
||||
|
||||
OnExit();
|
||||
|
||||
// all we have to do to exit from the loop is to (maybe) wake it up so that
|
||||
// it can notice that Exit() had been called
|
||||
//
|
||||
// in particular, do *not* use here calls such as PostQuitMessage() (under
|
||||
// MSW) which terminate the current event loop here because we're not sure
|
||||
// that it is going to be processed by the correct event loop: it would be
|
||||
// possible that another one is started and terminated by mistake if we do
|
||||
// this
|
||||
WakeUp();
|
||||
}
|
||||
|
||||
#endif // __WINDOWS__ || __WXMAC__ || __WXDFB__
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*****************************************************************************
|
||||
** Name: src/common/extended.c
|
||||
** Purpose: IEEE Extended<->Double routines to save floats to file
|
||||
** Maintainer: Ryan Norton
|
||||
** Modified by:
|
||||
** Created: 11/24/04
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "wx/defs.h"
|
||||
|
||||
#if wxUSE_APPLE_IEEE
|
||||
|
||||
#include "wx/math.h"
|
||||
|
||||
/* Copyright (C) 1989-1991 Ken Turkowski. <turk@computer.org>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Warranty Information
|
||||
* Even though I have reviewed this software, I make no warranty
|
||||
* or representation, either express or implied, with respect to this
|
||||
* software, its quality, accuracy, merchantability, or fitness for a
|
||||
* particular purpose. As a result, this software is provided "as is,"
|
||||
* and you, its user, are assuming the entire risk as to its quality
|
||||
* and accuracy.
|
||||
*
|
||||
* This code may be used and freely distributed as long as it includes
|
||||
* this copyright notice and the above warranty information.
|
||||
*
|
||||
* Machine-independent I/O routines for IEEE floating-point numbers.
|
||||
*
|
||||
* NaN's and infinities are converted to HUGE_VAL or HUGE, which
|
||||
* happens to be infinity on IEEE machines. Unfortunately, it is
|
||||
* impossible to preserve NaN's in a machine-independent way.
|
||||
* Infinities are, however, preserved on IEEE machines.
|
||||
*
|
||||
* These routines have been tested on the following machines:
|
||||
* Apple Macintosh, MPW 3.1 C compiler
|
||||
* Apple Macintosh, THINK C compiler
|
||||
* Silicon Graphics IRIS, MIPS compiler
|
||||
* Cray X/MP and Y/MP
|
||||
* Digital Equipment VAX
|
||||
* Sequent Balance (Multiprocesor 386)
|
||||
* NeXT
|
||||
*
|
||||
*
|
||||
* Implemented by Malcolm Slaney and Ken Turkowski.
|
||||
*
|
||||
* Malcolm Slaney contributions during 1988-1990 include big- and little-
|
||||
* endian file I/O, conversion to and from Motorola's extended 80-bit
|
||||
* floating-point format, and conversions to and from IEEE single-
|
||||
* precision floating-point format.
|
||||
*
|
||||
* In 1991, Ken Turkowski implemented the conversions to and from
|
||||
* IEEE double-precision format, added more precision to the extended
|
||||
* conversions, and accommodated conversions involving +/- infinity,
|
||||
* NaN's, and denormalized numbers.
|
||||
*/
|
||||
|
||||
#ifndef HUGE_VAL
|
||||
# define HUGE_VAL HUGE
|
||||
#endif /*HUGE_VAL*/
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* The following two routines make up for deficiencies in many
|
||||
* compilers to convert properly between unsigned integers and
|
||||
* floating-point. Some compilers which have this bug are the
|
||||
* THINK_C compiler for the Macintosh and the C compiler for the
|
||||
* Silicon Graphics MIPS-based Iris.
|
||||
****************************************************************/
|
||||
|
||||
#ifdef applec /* The Apple C compiler works */
|
||||
# define FloatToUnsigned(f) ((wxUint32)(f))
|
||||
# define UnsignedToFloat(u) ((wxFloat64)(u))
|
||||
#else /*applec*/
|
||||
# define FloatToUnsigned(f) ((wxUint32)(((wxInt32)((f) - 2147483648.0)) + 2147483647L) + 1)
|
||||
# define UnsignedToFloat(u) (((wxFloat64)((wxInt32)((u) - 2147483647L - 1))) + 2147483648.0)
|
||||
#endif /*applec*/
|
||||
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Extended precision IEEE floating-point conversion routines.
|
||||
* Extended is an 80-bit number as defined by Motorola,
|
||||
* with a sign bit, 15 bits of exponent (offset 16383?),
|
||||
* and a 64-bit mantissa, with no hidden bit.
|
||||
****************************************************************/
|
||||
|
||||
WXDLLIMPEXP_BASE wxFloat64 wxConvertFromIeeeExtended(const wxInt8 *bytes)
|
||||
{
|
||||
wxFloat64 f;
|
||||
wxInt32 expon;
|
||||
wxUint32 hiMant, loMant;
|
||||
|
||||
expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
|
||||
hiMant = ((wxUint32)(bytes[2] & 0xFF) << 24)
|
||||
| ((wxUint32)(bytes[3] & 0xFF) << 16)
|
||||
| ((wxUint32)(bytes[4] & 0xFF) << 8)
|
||||
| ((wxUint32)(bytes[5] & 0xFF));
|
||||
loMant = ((wxUint32)(bytes[6] & 0xFF) << 24)
|
||||
| ((wxUint32)(bytes[7] & 0xFF) << 16)
|
||||
| ((wxUint32)(bytes[8] & 0xFF) << 8)
|
||||
| ((wxUint32)(bytes[9] & 0xFF));
|
||||
|
||||
if (expon == 0 && hiMant == 0 && loMant == 0) {
|
||||
f = 0;
|
||||
}
|
||||
else {
|
||||
if (expon == 0x7FFF) { /* Infinity or NaN */
|
||||
f = HUGE_VAL;
|
||||
}
|
||||
else {
|
||||
expon -= 16383;
|
||||
f = ldexp(UnsignedToFloat(hiMant), expon-=31);
|
||||
f += ldexp(UnsignedToFloat(loMant), expon-=32);
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes[0] & 0x80)
|
||||
return -f;
|
||||
else
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
WXDLLIMPEXP_BASE void wxConvertToIeeeExtended(wxFloat64 num, wxInt8 *bytes)
|
||||
{
|
||||
wxInt32 sign;
|
||||
wxInt32 expon;
|
||||
wxFloat64 fMant, fsMant;
|
||||
wxUint32 hiMant, loMant;
|
||||
|
||||
if (num < 0) {
|
||||
sign = 0x8000;
|
||||
num *= -1;
|
||||
} else {
|
||||
sign = 0;
|
||||
}
|
||||
|
||||
if (num == 0) {
|
||||
expon = 0; hiMant = 0; loMant = 0;
|
||||
}
|
||||
else {
|
||||
fMant = frexp(num, &expon);
|
||||
if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */
|
||||
expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
|
||||
}
|
||||
else { /* Finite */
|
||||
expon += 16382;
|
||||
if (expon < 0) { /* denormalized */
|
||||
fMant = ldexp(fMant, expon);
|
||||
expon = 0;
|
||||
}
|
||||
expon |= sign;
|
||||
fMant = ldexp(fMant, 32); fsMant = floor(fMant); hiMant = FloatToUnsigned(fsMant);
|
||||
fMant = ldexp(fMant - fsMant, 32); fsMant = floor(fMant); loMant = FloatToUnsigned(fsMant);
|
||||
}
|
||||
}
|
||||
|
||||
bytes[0] = expon >> 8;
|
||||
bytes[1] = expon;
|
||||
bytes[2] = hiMant >> 24;
|
||||
bytes[3] = hiMant >> 16;
|
||||
bytes[4] = hiMant >> 8;
|
||||
bytes[5] = hiMant;
|
||||
bytes[6] = loMant >> 24;
|
||||
bytes[7] = loMant >> 16;
|
||||
bytes[8] = loMant >> 8;
|
||||
bytes[9] = loMant;
|
||||
}
|
||||
|
||||
#if WXWIN_COMPATIBILITY_2_8
|
||||
WXDLLIMPEXP_BASE wxFloat64 ConvertFromIeeeExtended(const wxInt8 *bytes)
|
||||
{
|
||||
return wxConvertFromIeeeExtended(bytes);
|
||||
}
|
||||
|
||||
WXDLLIMPEXP_BASE void ConvertToIeeeExtended(wxFloat64 num, wxInt8 *bytes)
|
||||
{
|
||||
wxConvertToIeeeExtended(num, bytes);
|
||||
}
|
||||
#endif // WXWIN_COMPATIBILITY_2_8
|
||||
|
||||
#endif /* wxUSE_APPLE_IEEE */
|
||||
@@ -0,0 +1,143 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/fdiodispatcher.cpp
|
||||
// Purpose: Implementation of common wxFDIODispatcher methods
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2007-05-13
|
||||
// Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/module.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include "wx/private/fdiodispatcher.h"
|
||||
|
||||
#include "wx/private/selectdispatcher.h"
|
||||
#ifdef __UNIX__
|
||||
#include "wx/unix/private/epolldispatcher.h"
|
||||
#endif
|
||||
|
||||
static
|
||||
wxFDIODispatcher *gs_dispatcher = NULL;
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFDIODispatcher
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/* static */
|
||||
wxFDIODispatcher *wxFDIODispatcher::Get()
|
||||
{
|
||||
if ( !gs_dispatcher )
|
||||
{
|
||||
#if wxUSE_EPOLL_DISPATCHER
|
||||
gs_dispatcher = wxEpollDispatcher::Create();
|
||||
if ( !gs_dispatcher )
|
||||
#endif // wxUSE_EPOLL_DISPATCHER
|
||||
#if wxUSE_SELECT_DISPATCHER
|
||||
gs_dispatcher = new wxSelectDispatcher();
|
||||
#endif // wxUSE_SELECT_DISPATCHER
|
||||
}
|
||||
|
||||
wxASSERT_MSG( gs_dispatcher, "failed to create any IO dispatchers" );
|
||||
|
||||
return gs_dispatcher;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void wxFDIODispatcher::DispatchPending()
|
||||
{
|
||||
if ( gs_dispatcher )
|
||||
gs_dispatcher->Dispatch(0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMappedFDIODispatcher
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxFDIOHandler *wxMappedFDIODispatcher::FindHandler(int fd) const
|
||||
{
|
||||
const wxFDIOHandlerMap::const_iterator it = m_handlers.find(fd);
|
||||
|
||||
return it == m_handlers.end() ? NULL : it->second.handler;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
wxMappedFDIODispatcher::RegisterFD(int fd, wxFDIOHandler *handler, int flags)
|
||||
{
|
||||
wxCHECK_MSG( handler, false, "handler can't be NULL" );
|
||||
|
||||
// notice that it's not an error to register a handler for the same fd
|
||||
// twice as it can be done with different flags -- but it is an error to
|
||||
// register different handlers
|
||||
wxFDIOHandlerMap::iterator i = m_handlers.find(fd);
|
||||
if ( i != m_handlers.end() )
|
||||
{
|
||||
wxASSERT_MSG( i->second.handler == handler,
|
||||
"registering different handler for the same fd?" );
|
||||
wxASSERT_MSG( i->second.flags != flags,
|
||||
"reregistering with the same flags?" );
|
||||
}
|
||||
|
||||
m_handlers[fd] = wxFDIOHandlerEntry(handler, flags);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
wxMappedFDIODispatcher::ModifyFD(int fd, wxFDIOHandler *handler, int flags)
|
||||
{
|
||||
wxCHECK_MSG( handler, false, "handler can't be NULL" );
|
||||
|
||||
wxFDIOHandlerMap::iterator i = m_handlers.find(fd);
|
||||
wxCHECK_MSG( i != m_handlers.end(), false,
|
||||
"modifying unregistered handler?" );
|
||||
|
||||
i->second = wxFDIOHandlerEntry(handler, flags);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxMappedFDIODispatcher::UnregisterFD(int fd)
|
||||
{
|
||||
wxFDIOHandlerMap::iterator i = m_handlers.find(fd);
|
||||
if ( i == m_handlers.end() )
|
||||
return false;
|
||||
|
||||
m_handlers.erase(i);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxSelectDispatcherModule
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxFDIODispatcherModule : public wxModule
|
||||
{
|
||||
public:
|
||||
virtual bool OnInit() wxOVERRIDE { return true; }
|
||||
virtual void OnExit() wxOVERRIDE { wxDELETE(gs_dispatcher); }
|
||||
|
||||
private:
|
||||
wxDECLARE_DYNAMIC_CLASS(wxFDIODispatcherModule);
|
||||
};
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxFDIODispatcherModule, wxModule);
|
||||
@@ -0,0 +1,398 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/ffile.cpp
|
||||
// Purpose: wxFFile encapsulates "FILE *" IO stream
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 14.07.99
|
||||
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_FFILE
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/intl.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/crt.h"
|
||||
#endif
|
||||
|
||||
#include "wx/filename.h"
|
||||
#include "wx/ffile.h"
|
||||
|
||||
// ============================================================================
|
||||
// implementation of wxFFile
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// opening the file
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxFFile::wxFFile(const wxString& filename, const wxString& mode)
|
||||
{
|
||||
m_fp = NULL;
|
||||
|
||||
(void)Open(filename, mode);
|
||||
}
|
||||
|
||||
bool wxFFile::Open(const wxString& filename, const wxString& mode)
|
||||
{
|
||||
wxASSERT_MSG( !m_fp, wxT("should close or detach the old file first") );
|
||||
|
||||
FILE* const fp = wxFopen(filename, mode);
|
||||
|
||||
if ( !fp )
|
||||
{
|
||||
wxLogSysError(_("can't open file '%s'"), filename);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Attach(fp, filename);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxFFile::Close()
|
||||
{
|
||||
if ( IsOpened() )
|
||||
{
|
||||
if ( fclose(m_fp) != 0 )
|
||||
{
|
||||
wxLogSysError(_("can't close file '%s'"), m_name.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_fp = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// read/write
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxFFile::ReadAll(wxString *str, const wxMBConv& conv)
|
||||
{
|
||||
wxCHECK_MSG( str, false, wxT("invalid parameter") );
|
||||
wxCHECK_MSG( IsOpened(), false, wxT("can't read from closed file") );
|
||||
wxCHECK_MSG( Length() >= 0, false, wxT("invalid length") );
|
||||
size_t length = wx_truncate_cast(size_t, Length());
|
||||
wxCHECK_MSG( (wxFileOffset)length == Length(), false, wxT("huge file not supported") );
|
||||
|
||||
clearerr(m_fp);
|
||||
|
||||
wxCharBuffer buf(length);
|
||||
|
||||
// note that real length may be less than file length for text files with DOS EOLs
|
||||
// ('\r's get dropped by CRT when reading which means that we have
|
||||
// realLen = fileLen - numOfLinesInTheFile)
|
||||
length = fread(buf.data(), 1, length, m_fp);
|
||||
|
||||
if ( Error() )
|
||||
{
|
||||
wxLogSysError(_("Read error on file '%s'"), m_name.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// shrink the buffer to possibly shorter data as explained above:
|
||||
buf.shrink(length);
|
||||
|
||||
wxString strTmp(buf, conv);
|
||||
str->swap(strTmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t wxFFile::Read(void *pBuf, size_t nCount)
|
||||
{
|
||||
if ( !nCount )
|
||||
return 0;
|
||||
|
||||
wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") );
|
||||
wxCHECK_MSG( IsOpened(), 0, wxT("can't read from closed file") );
|
||||
|
||||
size_t nRead = fread(pBuf, 1, nCount, m_fp);
|
||||
if ( (nRead < nCount) && Error() )
|
||||
{
|
||||
wxLogSysError(_("Read error on file '%s'"), m_name.c_str());
|
||||
}
|
||||
|
||||
return nRead;
|
||||
}
|
||||
|
||||
size_t wxFFile::Write(const void *pBuf, size_t nCount)
|
||||
{
|
||||
if ( !nCount )
|
||||
return 0;
|
||||
|
||||
wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") );
|
||||
wxCHECK_MSG( IsOpened(), 0, wxT("can't write to closed file") );
|
||||
|
||||
size_t nWritten = fwrite(pBuf, 1, nCount, m_fp);
|
||||
if ( nWritten < nCount )
|
||||
{
|
||||
wxLogSysError(_("Write error on file '%s'"), m_name.c_str());
|
||||
}
|
||||
|
||||
return nWritten;
|
||||
}
|
||||
|
||||
bool wxFFile::Write(const wxString& s, const wxMBConv& conv)
|
||||
{
|
||||
// Writing nothing always succeeds -- and simplifies the check for
|
||||
// conversion failure below.
|
||||
if ( s.empty() )
|
||||
return true;
|
||||
|
||||
const wxWX2MBbuf buf = s.mb_str(conv);
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
const size_t size = buf.length();
|
||||
|
||||
if ( !size )
|
||||
{
|
||||
// This means that the conversion failed as the original string wasn't
|
||||
// empty (we explicitly checked for this above) and in this case we
|
||||
// must fail too to indicate that we can't save the data.
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
const size_t size = s.length();
|
||||
#endif
|
||||
|
||||
return Write(buf, size) == size;
|
||||
}
|
||||
|
||||
bool wxFFile::Flush()
|
||||
{
|
||||
if ( IsOpened() )
|
||||
{
|
||||
if ( fflush(m_fp) != 0 )
|
||||
{
|
||||
wxLogSysError(_("failed to flush the file '%s'"), m_name.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// seeking
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxFFile::Seek(wxFileOffset ofs, wxSeekMode mode)
|
||||
{
|
||||
wxCHECK_MSG( IsOpened(), false, wxT("can't seek on closed file") );
|
||||
|
||||
int origin;
|
||||
switch ( mode )
|
||||
{
|
||||
default:
|
||||
wxFAIL_MSG(wxT("unknown seek mode"));
|
||||
wxFALLTHROUGH;
|
||||
|
||||
case wxFromStart:
|
||||
origin = SEEK_SET;
|
||||
break;
|
||||
|
||||
case wxFromCurrent:
|
||||
origin = SEEK_CUR;
|
||||
break;
|
||||
|
||||
case wxFromEnd:
|
||||
origin = SEEK_END;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef wxHAS_LARGE_FFILES
|
||||
if ((long)ofs != ofs)
|
||||
{
|
||||
wxLogError(_("Seek error on file '%s' (large files not supported by stdio)"), m_name.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( wxFseek(m_fp, (long)ofs, origin) != 0 )
|
||||
#else
|
||||
if ( wxFseek(m_fp, ofs, origin) != 0 )
|
||||
#endif
|
||||
{
|
||||
wxLogSysError(_("Seek error on file '%s'"), m_name.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
wxFileOffset wxFFile::Tell() const
|
||||
{
|
||||
wxCHECK_MSG( IsOpened(), wxInvalidOffset,
|
||||
wxT("wxFFile::Tell(): file is closed!") );
|
||||
|
||||
wxFileOffset rc = wxFtell(m_fp);
|
||||
if ( rc == wxInvalidOffset )
|
||||
{
|
||||
wxLogSysError(_("Can't find current position in file '%s'"),
|
||||
m_name.c_str());
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
wxFileOffset wxFFile::Length() const
|
||||
{
|
||||
wxCHECK_MSG( IsOpened(), wxInvalidOffset,
|
||||
wxT("wxFFile::Length(): file is closed!") );
|
||||
|
||||
wxFileOffset posOld = Tell();
|
||||
if ( posOld != wxInvalidOffset )
|
||||
{
|
||||
wxFFile& self = *const_cast<wxFFile*>(this);
|
||||
|
||||
if ( self.SeekEnd() )
|
||||
{
|
||||
wxFileOffset len = Tell();
|
||||
|
||||
(void)self.Seek(posOld);
|
||||
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
return wxInvalidOffset;
|
||||
}
|
||||
|
||||
bool wxFFile::Eof() const
|
||||
{
|
||||
wxCHECK_MSG( IsOpened(), false,
|
||||
wxT("wxFFile::Eof(): file is closed!") );
|
||||
return feof(m_fp) != 0;
|
||||
}
|
||||
|
||||
bool wxFFile::Error() const
|
||||
{
|
||||
wxCHECK_MSG( IsOpened(), false,
|
||||
wxT("wxFFile::Error(): file is closed!") );
|
||||
return ferror(m_fp) != 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// implementation of wxTempFFile
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// construction
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxTempFFile::wxTempFFile(const wxString& strName)
|
||||
{
|
||||
Open(strName);
|
||||
}
|
||||
|
||||
bool wxTempFFile::Open(const wxString& strName)
|
||||
{
|
||||
// we must have an absolute filename because otherwise CreateTempFileName()
|
||||
// would create the temp file in $TMP (i.e. the system standard location
|
||||
// for the temp files) which might be on another volume/drive/mount and
|
||||
// wxRename()ing it later to m_strName from Commit() would then fail
|
||||
//
|
||||
// with the absolute filename, the temp file is created in the same
|
||||
// directory as this one which ensures that wxRename() may work later
|
||||
wxFileName fn(strName);
|
||||
if ( !fn.IsAbsolute() )
|
||||
{
|
||||
fn.Normalize(wxPATH_NORM_ABSOLUTE);
|
||||
}
|
||||
|
||||
m_strName = fn.GetFullPath();
|
||||
|
||||
m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file);
|
||||
|
||||
if ( m_strTemp.empty() )
|
||||
{
|
||||
// CreateTempFileName() failed
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __UNIX__
|
||||
// the temp file should have the same permissions as the original one
|
||||
mode_t mode;
|
||||
|
||||
wxStructStat st;
|
||||
if ( stat( (const char*) m_strName.fn_str(), &st) == 0 )
|
||||
{
|
||||
mode = st.st_mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// file probably didn't exist, just give it the default mode _using_
|
||||
// user's umask (new files creation should respect umask)
|
||||
mode_t mask = umask(0777);
|
||||
mode = 0666 & ~mask;
|
||||
umask(mask);
|
||||
}
|
||||
|
||||
if ( chmod( (const char*) m_strTemp.fn_str(), mode) == -1 )
|
||||
{
|
||||
wxLogSysError(_("Failed to set temporary file permissions"));
|
||||
}
|
||||
#endif // Unix
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// destruction
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxTempFFile::~wxTempFFile()
|
||||
{
|
||||
if ( IsOpened() )
|
||||
Discard();
|
||||
}
|
||||
|
||||
bool wxTempFFile::Commit()
|
||||
{
|
||||
m_file.Close();
|
||||
|
||||
if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) {
|
||||
wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !wxRenameFile(m_strTemp, m_strName) ) {
|
||||
wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxTempFFile::Discard()
|
||||
{
|
||||
m_file.Close();
|
||||
if ( wxRemove(m_strTemp) != 0 )
|
||||
{
|
||||
wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_FFILE
|
||||
@@ -0,0 +1,630 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/file.cpp
|
||||
// Purpose: wxFile - encapsulates low-level "file descriptor"
|
||||
// wxTempFile
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 29/01/98
|
||||
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_FILE
|
||||
|
||||
// standard
|
||||
#if defined(__WINDOWS__) && !defined(__GNUWIN32__)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOSERVICE
|
||||
#define NOIME
|
||||
#define NOATOM
|
||||
#define NOGDI
|
||||
#define NOGDICAPMASKS
|
||||
#define NOMETAFILE
|
||||
#define NOMINMAX
|
||||
#define NOMSG
|
||||
#define NOOPENFILE
|
||||
#define NORASTEROPS
|
||||
#define NOSCROLL
|
||||
#define NOSOUND
|
||||
#define NOSYSMETRICS
|
||||
#define NOTEXTMETRIC
|
||||
#define NOWH
|
||||
#define NOCOMM
|
||||
#define NOKANJI
|
||||
#define NOCRYPT
|
||||
#define NOMCX
|
||||
|
||||
#elif (defined(__UNIX__) || defined(__GNUWIN32__))
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef __GNUWIN32__
|
||||
#include "wx/msw/wrapwin.h"
|
||||
#endif
|
||||
#elif (defined(__WXSTUBS__))
|
||||
// Have to ifdef this for different environments
|
||||
#include <io.h>
|
||||
#elif (defined(__WXMAC__))
|
||||
#if __MSL__ < 0x6000
|
||||
int access( const char *path, int mode ) { return 0 ; }
|
||||
#else
|
||||
int _access( const char *path, int mode ) { return 0 ; }
|
||||
#endif
|
||||
char* mktemp( char * path ) { return path ;}
|
||||
#include <stat.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#error "Please specify the header with file functions declarations."
|
||||
#endif //Win/UNIX
|
||||
|
||||
#include <stdio.h> // SEEK_xxx constants
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
// Windows compilers don't have these constants
|
||||
#ifndef W_OK
|
||||
enum
|
||||
{
|
||||
F_OK = 0, // test for existence
|
||||
X_OK = 1, // execute permission
|
||||
W_OK = 2, // write
|
||||
R_OK = 4 // read
|
||||
};
|
||||
#endif // W_OK
|
||||
|
||||
// wxWidgets
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/string.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/crt.h"
|
||||
#endif // !WX_PRECOMP
|
||||
|
||||
#include "wx/filename.h"
|
||||
#include "wx/file.h"
|
||||
#include "wx/filefn.h"
|
||||
|
||||
// there is no distinction between text and binary files under Unix, so define
|
||||
// O_BINARY as 0 if the system headers don't do it already
|
||||
#if defined(__UNIX__) && !defined(O_BINARY)
|
||||
#define O_BINARY (0)
|
||||
#endif //__UNIX__
|
||||
|
||||
// ============================================================================
|
||||
// implementation of wxFile
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// static functions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxFile::Exists(const wxString& name)
|
||||
{
|
||||
return wxFileExists(name);
|
||||
}
|
||||
|
||||
bool wxFile::Access(const wxString& name, OpenMode mode)
|
||||
{
|
||||
int how;
|
||||
|
||||
switch ( mode )
|
||||
{
|
||||
default:
|
||||
wxFAIL_MSG(wxT("bad wxFile::Access mode parameter."));
|
||||
wxFALLTHROUGH;
|
||||
|
||||
case read:
|
||||
how = R_OK;
|
||||
break;
|
||||
|
||||
case write:
|
||||
how = W_OK;
|
||||
break;
|
||||
|
||||
case read_write:
|
||||
how = R_OK | W_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
return wxAccess(name, how) == 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// opening/closing
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// ctors
|
||||
wxFile::wxFile(const wxString& fileName, OpenMode mode)
|
||||
{
|
||||
m_fd = fd_invalid;
|
||||
m_lasterror = 0;
|
||||
|
||||
Open(fileName, mode);
|
||||
}
|
||||
|
||||
bool wxFile::CheckForError(wxFileOffset rc) const
|
||||
{
|
||||
if ( rc != -1 )
|
||||
return false;
|
||||
|
||||
const_cast<wxFile *>(this)->m_lasterror = errno;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// create the file, fail if it already exists and bOverwrite
|
||||
bool wxFile::Create(const wxString& fileName, bool bOverwrite, int accessMode)
|
||||
{
|
||||
// if bOverwrite we create a new file or truncate the existing one,
|
||||
// otherwise we only create the new file and fail if it already exists
|
||||
int fildes = wxOpen( fileName,
|
||||
O_BINARY | O_WRONLY | O_CREAT |
|
||||
(bOverwrite ? O_TRUNC : O_EXCL),
|
||||
accessMode );
|
||||
if ( CheckForError(fildes) )
|
||||
{
|
||||
wxLogSysError(_("can't create file '%s'"), fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
Attach(fildes);
|
||||
return true;
|
||||
}
|
||||
|
||||
// open the file
|
||||
bool wxFile::Open(const wxString& fileName, OpenMode mode, int accessMode)
|
||||
{
|
||||
int flags = O_BINARY;
|
||||
|
||||
switch ( mode )
|
||||
{
|
||||
case read:
|
||||
flags |= O_RDONLY;
|
||||
break;
|
||||
|
||||
case write_append:
|
||||
if ( wxFile::Exists(fileName) )
|
||||
{
|
||||
flags |= O_WRONLY | O_APPEND;
|
||||
break;
|
||||
}
|
||||
//else: fall through as write_append is the same as write if the
|
||||
// file doesn't exist
|
||||
wxFALLTHROUGH;
|
||||
|
||||
case write:
|
||||
flags |= O_WRONLY | O_CREAT | O_TRUNC;
|
||||
break;
|
||||
|
||||
case write_excl:
|
||||
flags |= O_WRONLY | O_CREAT | O_EXCL;
|
||||
break;
|
||||
|
||||
case read_write:
|
||||
flags |= O_RDWR;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
// only read/write bits for "all" are supported by this function under
|
||||
// Windows, and VC++ 8 returns EINVAL if any other bits are used in
|
||||
// accessMode, so clear them as they have at best no effect anyhow
|
||||
accessMode &= wxS_IRUSR | wxS_IWUSR;
|
||||
#endif // __WINDOWS__
|
||||
|
||||
int fildes = wxOpen( fileName, flags, accessMode);
|
||||
|
||||
if ( CheckForError(fildes) )
|
||||
{
|
||||
wxLogSysError(_("can't open file '%s'"), fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
Attach(fildes);
|
||||
return true;
|
||||
}
|
||||
|
||||
// close
|
||||
bool wxFile::Close()
|
||||
{
|
||||
if ( IsOpened() ) {
|
||||
if ( CheckForError(wxClose(m_fd)) )
|
||||
{
|
||||
wxLogSysError(_("can't close file descriptor %d"), m_fd);
|
||||
m_fd = fd_invalid;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_fd = fd_invalid;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// read/write
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxFile::ReadAll(wxString *str, const wxMBConv& conv)
|
||||
{
|
||||
wxCHECK_MSG( str, false, wxS("Output string must be non-NULL") );
|
||||
|
||||
static const ssize_t READSIZE = 4096;
|
||||
|
||||
wxCharBuffer buf;
|
||||
|
||||
ssize_t length = Length();
|
||||
if ( length != -1 )
|
||||
{
|
||||
wxCHECK_MSG( (wxFileOffset)length == Length(), false, wxT("huge file not supported") );
|
||||
|
||||
if ( !buf.extend(length) )
|
||||
return false;
|
||||
|
||||
char* p = buf.data();
|
||||
for ( ;; )
|
||||
{
|
||||
ssize_t nread = Read(p, length > READSIZE ? READSIZE : length);
|
||||
if ( nread == wxInvalidOffset )
|
||||
return false;
|
||||
|
||||
if ( nread == 0 )
|
||||
{
|
||||
// We have reached EOF before reading the entire length of the
|
||||
// file. This can happen for some special files (e.g. those
|
||||
// under /sys on Linux systems) or even for regular files if
|
||||
// another process has truncated the file since we started
|
||||
// reading it, so deal with it gracefully.
|
||||
buf.shrink(p - buf.data());
|
||||
break;
|
||||
}
|
||||
|
||||
p += nread;
|
||||
length -= nread;
|
||||
|
||||
if ( !length )
|
||||
{
|
||||
// Notice that we don't keep reading after getting the expected
|
||||
// number of bytes, even though in principle a situation
|
||||
// similar to the one described above, with another process
|
||||
// extending the file since we started to read it, is possible.
|
||||
// But returning just the data that was in the file when we
|
||||
// originally started reading it isn't really wrong in this
|
||||
// case, so keep things simple and just do it like this.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // File is not seekable
|
||||
{
|
||||
for ( ;; )
|
||||
{
|
||||
const size_t len = buf.length();
|
||||
if ( !buf.extend(len + READSIZE) )
|
||||
return false;
|
||||
|
||||
ssize_t nread = Read(buf.data() + len, READSIZE);
|
||||
if ( nread == wxInvalidOffset )
|
||||
return false;
|
||||
|
||||
if ( nread < READSIZE )
|
||||
{
|
||||
// We have reached EOF.
|
||||
buf.shrink(len + nread);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str->assign(buf, conv);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// read
|
||||
ssize_t wxFile::Read(void *pBuf, size_t nCount)
|
||||
{
|
||||
if ( !nCount )
|
||||
return 0;
|
||||
|
||||
wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
|
||||
|
||||
ssize_t iRc = wxRead(m_fd, pBuf, nCount);
|
||||
|
||||
if ( CheckForError(iRc) )
|
||||
{
|
||||
wxLogSysError(_("can't read from file descriptor %d"), m_fd);
|
||||
return wxInvalidOffset;
|
||||
}
|
||||
|
||||
return iRc;
|
||||
}
|
||||
|
||||
// write
|
||||
size_t wxFile::Write(const void *pBuf, size_t nCount)
|
||||
{
|
||||
if ( !nCount )
|
||||
return 0;
|
||||
|
||||
wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
|
||||
|
||||
ssize_t iRc = wxWrite(m_fd, pBuf, nCount);
|
||||
|
||||
if ( CheckForError(iRc) )
|
||||
{
|
||||
wxLogSysError(_("can't write to file descriptor %d"), m_fd);
|
||||
iRc = 0;
|
||||
}
|
||||
|
||||
return iRc;
|
||||
}
|
||||
|
||||
bool wxFile::Write(const wxString& s, const wxMBConv& conv)
|
||||
{
|
||||
// Writing nothing always succeeds -- and simplifies the check for
|
||||
// conversion failure below.
|
||||
if ( s.empty() )
|
||||
return true;
|
||||
|
||||
const wxWX2MBbuf buf = s.mb_str(conv);
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
const size_t size = buf.length();
|
||||
|
||||
if ( !size )
|
||||
{
|
||||
// This means that the conversion failed as the original string wasn't
|
||||
// empty (we explicitly checked for this above) and in this case we
|
||||
// must fail too to indicate that we can't save the data.
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
const size_t size = s.length();
|
||||
#endif
|
||||
|
||||
return Write(buf, size) == size;
|
||||
}
|
||||
|
||||
// flush
|
||||
bool wxFile::Flush()
|
||||
{
|
||||
#ifdef HAVE_FSYNC
|
||||
// fsync() only works on disk files and returns errors for pipes, don't
|
||||
// call it then
|
||||
if ( IsOpened() && GetKind() == wxFILE_KIND_DISK )
|
||||
{
|
||||
if ( CheckForError(wxFsync(m_fd)) )
|
||||
{
|
||||
wxLogSysError(_("can't flush file descriptor %d"), m_fd);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif // HAVE_FSYNC
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// seek
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// seek
|
||||
wxFileOffset wxFile::Seek(wxFileOffset ofs, wxSeekMode mode)
|
||||
{
|
||||
wxASSERT_MSG( IsOpened(), wxT("can't seek on closed file") );
|
||||
wxCHECK_MSG( ofs != wxInvalidOffset || mode != wxFromStart,
|
||||
wxInvalidOffset,
|
||||
wxT("invalid absolute file offset") );
|
||||
|
||||
int origin;
|
||||
switch ( mode ) {
|
||||
default:
|
||||
wxFAIL_MSG(wxT("unknown seek origin"));
|
||||
wxFALLTHROUGH;
|
||||
case wxFromStart:
|
||||
origin = SEEK_SET;
|
||||
break;
|
||||
|
||||
case wxFromCurrent:
|
||||
origin = SEEK_CUR;
|
||||
break;
|
||||
|
||||
case wxFromEnd:
|
||||
origin = SEEK_END;
|
||||
break;
|
||||
}
|
||||
|
||||
wxFileOffset iRc = wxSeek(m_fd, ofs, origin);
|
||||
if ( CheckForError(iRc) )
|
||||
{
|
||||
wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
|
||||
}
|
||||
|
||||
return iRc;
|
||||
}
|
||||
|
||||
// get current file offset
|
||||
wxFileOffset wxFile::Tell() const
|
||||
{
|
||||
wxASSERT( IsOpened() );
|
||||
|
||||
wxFileOffset iRc = wxTell(m_fd);
|
||||
if ( CheckForError(iRc) )
|
||||
{
|
||||
wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
|
||||
}
|
||||
|
||||
return iRc;
|
||||
}
|
||||
|
||||
// get current file length
|
||||
wxFileOffset wxFile::Length() const
|
||||
{
|
||||
wxASSERT( IsOpened() );
|
||||
|
||||
wxFileOffset iRc = Tell();
|
||||
if ( iRc != wxInvalidOffset ) {
|
||||
wxFileOffset iLen = const_cast<wxFile *>(this)->SeekEnd();
|
||||
if ( iLen != wxInvalidOffset ) {
|
||||
// restore old position
|
||||
if (const_cast<wxFile*>(this)->Seek(iRc) == wxInvalidOffset)
|
||||
{
|
||||
// error
|
||||
iLen = wxInvalidOffset;
|
||||
}
|
||||
}
|
||||
|
||||
iRc = iLen;
|
||||
}
|
||||
|
||||
if ( iRc == wxInvalidOffset )
|
||||
{
|
||||
// last error was already set by Tell()
|
||||
wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd);
|
||||
}
|
||||
|
||||
return iRc;
|
||||
}
|
||||
|
||||
// is end of file reached?
|
||||
bool wxFile::Eof() const
|
||||
{
|
||||
wxASSERT( IsOpened() );
|
||||
|
||||
wxFileOffset iRc;
|
||||
|
||||
#if defined(__UNIX__) || defined(__GNUWIN32__)
|
||||
// @@ this doesn't work, of course, on unseekable file descriptors
|
||||
wxFileOffset ofsCur = Tell(),
|
||||
ofsMax = Length();
|
||||
if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
|
||||
iRc = wxInvalidOffset;
|
||||
else
|
||||
iRc = ofsCur == ofsMax;
|
||||
#else // Windows and "native" compiler
|
||||
iRc = wxEof(m_fd);
|
||||
#endif // Windows/Unix
|
||||
|
||||
if ( iRc == 0 )
|
||||
return false;
|
||||
|
||||
if ( iRc == wxInvalidOffset )
|
||||
{
|
||||
wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// implementation of wxTempFile
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// construction
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxTempFile::wxTempFile(const wxString& strName)
|
||||
{
|
||||
Open(strName);
|
||||
}
|
||||
|
||||
bool wxTempFile::Open(const wxString& strName)
|
||||
{
|
||||
// we must have an absolute filename because otherwise CreateTempFileName()
|
||||
// would create the temp file in $TMP (i.e. the system standard location
|
||||
// for the temp files) which might be on another volume/drive/mount and
|
||||
// wxRename()ing it later to m_strName from Commit() would then fail
|
||||
//
|
||||
// with the absolute filename, the temp file is created in the same
|
||||
// directory as this one which ensures that wxRename() may work later
|
||||
wxFileName fn(strName);
|
||||
if ( !fn.IsAbsolute() )
|
||||
{
|
||||
fn.Normalize(wxPATH_NORM_ABSOLUTE);
|
||||
}
|
||||
|
||||
m_strName = fn.GetFullPath();
|
||||
|
||||
m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file);
|
||||
|
||||
if ( m_strTemp.empty() )
|
||||
{
|
||||
// CreateTempFileName() failed
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __UNIX__
|
||||
// the temp file should have the same permissions as the original one
|
||||
mode_t mode;
|
||||
|
||||
wxStructStat st;
|
||||
if ( stat( (const char*) m_strName.fn_str(), &st) == 0 )
|
||||
{
|
||||
mode = st.st_mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// file probably didn't exist, just give it the default mode _using_
|
||||
// user's umask (new files creation should respect umask)
|
||||
mode_t mask = umask(0777);
|
||||
mode = 0666 & ~mask;
|
||||
umask(mask);
|
||||
}
|
||||
|
||||
if ( chmod( (const char*) m_strTemp.fn_str(), mode) == -1 )
|
||||
{
|
||||
wxLogSysError(_("Failed to set temporary file permissions"));
|
||||
}
|
||||
#endif // Unix
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// destruction
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxTempFile::~wxTempFile()
|
||||
{
|
||||
if ( IsOpened() )
|
||||
Discard();
|
||||
}
|
||||
|
||||
bool wxTempFile::Commit()
|
||||
{
|
||||
m_file.Close();
|
||||
|
||||
if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) {
|
||||
wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !wxRenameFile(m_strTemp, m_strName) ) {
|
||||
wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxTempFile::Discard()
|
||||
{
|
||||
m_file.Close();
|
||||
if ( wxRemove(m_strTemp) != 0 )
|
||||
{
|
||||
wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_FILE
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/fileback.cpp
|
||||
// Purpose: Back an input stream with memory or a file
|
||||
// Author: Mike Wetherell
|
||||
// Copyright: (c) 2006 Mike Wetherell
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_FILESYSTEM
|
||||
|
||||
#include "wx/private/fileback.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/utils.h"
|
||||
#include "wx/log.h"
|
||||
#endif
|
||||
|
||||
#include "wx/private/filename.h"
|
||||
|
||||
// Prefer wxFFile unless wxFile has large file support but wxFFile does not.
|
||||
//
|
||||
#if wxUSE_FFILE && (defined wxHAS_LARGE_FFILES || !defined wxHAS_LARGE_FILES)
|
||||
typedef wxFFile wxBFFile;
|
||||
static const bool wxBadSeek = false;
|
||||
#else
|
||||
typedef wxFile wxBFFile;
|
||||
static const wxFileOffset wxBadSeek = wxInvalidOffset;
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Backing file implementation
|
||||
|
||||
class wxBackingFileImpl
|
||||
{
|
||||
public:
|
||||
wxBackingFileImpl(wxInputStream *stream,
|
||||
size_t bufsize,
|
||||
const wxString& prefix);
|
||||
~wxBackingFileImpl();
|
||||
|
||||
void Release() { if (--m_refcount == 0) delete this; }
|
||||
wxBackingFileImpl *AddRef() { m_refcount++; return this; }
|
||||
|
||||
wxStreamError ReadAt(wxFileOffset pos, void *buffer, size_t *size);
|
||||
wxFileOffset GetLength() const;
|
||||
|
||||
private:
|
||||
int m_refcount;
|
||||
|
||||
wxInputStream *m_stream;
|
||||
wxStreamError m_parenterror;
|
||||
|
||||
char *m_buf;
|
||||
size_t m_bufsize;
|
||||
size_t m_buflen;
|
||||
|
||||
wxString m_prefix;
|
||||
wxString m_filename;
|
||||
wxBFFile m_file;
|
||||
wxFileOffset m_filelen;
|
||||
};
|
||||
|
||||
wxBackingFileImpl::wxBackingFileImpl(wxInputStream *stream,
|
||||
size_t bufsize,
|
||||
const wxString& prefix)
|
||||
: m_refcount(1),
|
||||
m_stream(stream),
|
||||
m_parenterror(wxSTREAM_NO_ERROR),
|
||||
m_buf(NULL),
|
||||
m_bufsize(bufsize),
|
||||
m_buflen(0),
|
||||
m_prefix(prefix),
|
||||
m_filelen(0)
|
||||
{
|
||||
wxFileOffset len = m_stream->GetLength();
|
||||
|
||||
if (len >= 0 && len + size_t(1) < m_bufsize)
|
||||
m_bufsize = size_t(len + 1);
|
||||
|
||||
if (m_bufsize)
|
||||
m_buf = new char[m_bufsize];
|
||||
}
|
||||
|
||||
wxBackingFileImpl::~wxBackingFileImpl()
|
||||
{
|
||||
delete m_stream;
|
||||
delete [] m_buf;
|
||||
|
||||
if (!m_filename.empty())
|
||||
wxRemoveFile(m_filename);
|
||||
}
|
||||
|
||||
wxStreamError wxBackingFileImpl::ReadAt(wxFileOffset pos,
|
||||
void *buffer,
|
||||
size_t *size)
|
||||
{
|
||||
size_t reqestedSize = *size;
|
||||
*size = 0;
|
||||
|
||||
// size1 is the number of bytes it will read directly from the backing
|
||||
// file. size2 is any remaining bytes not yet backed, these are returned
|
||||
// from the buffer or read from the parent stream.
|
||||
size_t size1, size2;
|
||||
|
||||
if (pos + reqestedSize <= m_filelen + size_t(0)) {
|
||||
size1 = reqestedSize;
|
||||
size2 = 0;
|
||||
} else if (pos < m_filelen) {
|
||||
size1 = size_t(m_filelen - pos);
|
||||
size2 = reqestedSize - size1;
|
||||
} else {
|
||||
size1 = 0;
|
||||
size2 = reqestedSize;
|
||||
}
|
||||
|
||||
if (pos < 0)
|
||||
return wxSTREAM_READ_ERROR;
|
||||
|
||||
// read the backing file
|
||||
if (size1) {
|
||||
if (m_file.Seek(pos) == wxBadSeek)
|
||||
return wxSTREAM_READ_ERROR;
|
||||
|
||||
ssize_t n = m_file.Read(buffer, size1);
|
||||
if (n > 0) {
|
||||
*size = n;
|
||||
pos += n;
|
||||
}
|
||||
|
||||
if (*size < size1)
|
||||
return wxSTREAM_READ_ERROR;
|
||||
}
|
||||
|
||||
// read from the buffer or parent stream
|
||||
if (size2)
|
||||
{
|
||||
while (*size < reqestedSize)
|
||||
{
|
||||
// if pos is further ahead than the parent has been read so far,
|
||||
// then read forward in the parent stream
|
||||
while (pos - m_filelen + size_t(0) >= m_buflen)
|
||||
{
|
||||
// if the parent is small enough, don't use a backing file
|
||||
// just the buffer memory
|
||||
if (!m_stream && m_filelen == 0)
|
||||
return m_parenterror;
|
||||
|
||||
// before refilling the buffer write out the current buffer
|
||||
// to the backing file if there is anything in it
|
||||
if (m_buflen)
|
||||
{
|
||||
if (!m_file.IsOpened())
|
||||
if (!wxCreateTempFile(m_prefix, &m_file, &m_filename))
|
||||
return wxSTREAM_READ_ERROR;
|
||||
|
||||
if (m_file.Seek(m_filelen) == wxBadSeek)
|
||||
return wxSTREAM_READ_ERROR;
|
||||
|
||||
size_t count = m_file.Write(m_buf, m_buflen);
|
||||
m_filelen += count;
|
||||
|
||||
if (count < m_buflen) {
|
||||
wxDELETE(m_stream);
|
||||
if (count > 0) {
|
||||
wxDELETEA(m_buf);
|
||||
m_buflen = 0;
|
||||
}
|
||||
m_parenterror = wxSTREAM_READ_ERROR;
|
||||
return m_parenterror;
|
||||
}
|
||||
|
||||
m_buflen = 0;
|
||||
|
||||
if (!m_stream) {
|
||||
wxDELETEA(m_buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_stream)
|
||||
return m_parenterror;
|
||||
|
||||
// refill buffer
|
||||
m_buflen = m_stream->Read(m_buf, m_bufsize).LastRead();
|
||||
|
||||
if (m_buflen < m_bufsize) {
|
||||
m_parenterror = m_stream->GetLastError();
|
||||
if (m_parenterror == wxSTREAM_NO_ERROR)
|
||||
m_parenterror = wxSTREAM_EOF;
|
||||
wxDELETE(m_stream);
|
||||
}
|
||||
}
|
||||
|
||||
// copy to the user's buffer
|
||||
size_t start = size_t(pos - m_filelen);
|
||||
size_t len = wxMin(m_buflen - start, reqestedSize - *size);
|
||||
|
||||
memcpy((char*)buffer + *size, m_buf + start, len);
|
||||
*size += len;
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
|
||||
return wxSTREAM_NO_ERROR;
|
||||
}
|
||||
|
||||
wxFileOffset wxBackingFileImpl::GetLength() const
|
||||
{
|
||||
if (m_parenterror != wxSTREAM_EOF) {
|
||||
wxLogNull nolog;
|
||||
return m_stream->GetLength();
|
||||
}
|
||||
return m_filelen + m_buflen;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Backing File, the handle part
|
||||
|
||||
wxBackingFile::wxBackingFile(wxInputStream *stream,
|
||||
size_t bufsize,
|
||||
const wxString& prefix)
|
||||
: m_impl(new wxBackingFileImpl(stream, bufsize, prefix))
|
||||
{
|
||||
}
|
||||
|
||||
wxBackingFile::wxBackingFile(const wxBackingFile& backer)
|
||||
: m_impl(backer.m_impl ? backer.m_impl->AddRef() : NULL)
|
||||
{
|
||||
}
|
||||
|
||||
wxBackingFile& wxBackingFile::operator=(const wxBackingFile& backer)
|
||||
{
|
||||
if (backer.m_impl != m_impl) {
|
||||
if (m_impl)
|
||||
m_impl->Release();
|
||||
|
||||
m_impl = backer.m_impl;
|
||||
|
||||
if (m_impl)
|
||||
m_impl->AddRef();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxBackingFile::~wxBackingFile()
|
||||
{
|
||||
if (m_impl)
|
||||
m_impl->Release();
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Input stream
|
||||
|
||||
wxBackedInputStream::wxBackedInputStream(const wxBackingFile& backer)
|
||||
: m_backer(backer),
|
||||
m_pos(0)
|
||||
{
|
||||
}
|
||||
|
||||
wxFileOffset wxBackedInputStream::GetLength() const
|
||||
{
|
||||
return m_backer.m_impl->GetLength();
|
||||
}
|
||||
|
||||
wxFileOffset wxBackedInputStream::FindLength() const
|
||||
{
|
||||
wxFileOffset len = GetLength();
|
||||
|
||||
if (len == wxInvalidOffset && IsOk()) {
|
||||
// read a byte at 7ff...ffe
|
||||
wxFileOffset pos = 1;
|
||||
pos <<= sizeof(pos) * 8 - 1;
|
||||
pos = ~pos - 1;
|
||||
char ch;
|
||||
size_t size = 1;
|
||||
m_backer.m_impl->ReadAt(pos, &ch, &size);
|
||||
len = GetLength();
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t wxBackedInputStream::OnSysRead(void *buffer, size_t size)
|
||||
{
|
||||
if (!IsOk())
|
||||
return 0;
|
||||
|
||||
m_lasterror = m_backer.m_impl->ReadAt(m_pos, buffer, &size);
|
||||
m_pos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
wxFileOffset wxBackedInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case wxFromCurrent:
|
||||
{
|
||||
m_pos += pos;
|
||||
break;
|
||||
}
|
||||
case wxFromEnd:
|
||||
{
|
||||
wxFileOffset len = GetLength();
|
||||
if (len == wxInvalidOffset)
|
||||
return wxInvalidOffset;
|
||||
m_pos = len + pos;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
m_pos = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
wxFileOffset wxBackedInputStream::OnSysTell() const
|
||||
{
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
#endif // wxUSE_FILESYSTEM
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,715 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/filesys.cpp
|
||||
// Purpose: wxFileSystem class - interface for opening files
|
||||
// Author: Vaclav Slavik
|
||||
// Copyright: (c) 1999 Vaclav Slavik
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
|
||||
#if wxUSE_FILESYSTEM
|
||||
|
||||
#include "wx/filesys.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/log.h"
|
||||
#include "wx/module.h"
|
||||
#endif
|
||||
|
||||
#include "wx/sysopt.h"
|
||||
#include "wx/wfstream.h"
|
||||
#include "wx/mimetype.h"
|
||||
#include "wx/filename.h"
|
||||
#include "wx/tokenzr.h"
|
||||
#include "wx/private/fileback.h"
|
||||
#include "wx/utils.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFSFile
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const wxString& wxFSFile::GetMimeType() const
|
||||
{
|
||||
if ( m_MimeType.empty() && !m_Location.empty() )
|
||||
{
|
||||
wxConstCast(this, wxFSFile)->m_MimeType =
|
||||
wxFileSystemHandler::GetMimeTypeFromExt(m_Location);
|
||||
}
|
||||
|
||||
return m_MimeType;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFileSystemHandler
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxIMPLEMENT_ABSTRACT_CLASS(wxFileSystemHandler, wxObject);
|
||||
|
||||
|
||||
/* static */
|
||||
wxString wxFileSystemHandler::GetMimeTypeFromExt(const wxString& location)
|
||||
{
|
||||
wxString ext, mime;
|
||||
wxString loc = GetRightLocation(location);
|
||||
int l = loc.length(), l2;
|
||||
|
||||
l2 = l;
|
||||
for (int i = l-1; i >= 0; i--)
|
||||
{
|
||||
wxChar c;
|
||||
c = loc[(unsigned int) i];
|
||||
if ( c == wxT('#') )
|
||||
l2 = i + 1;
|
||||
if ( c == wxT('.') )
|
||||
{
|
||||
ext = loc.Right(l2-i-1);
|
||||
break;
|
||||
}
|
||||
if ( (c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':')) )
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
#if wxUSE_MIMETYPE
|
||||
static bool s_MinimalMimeEnsured = false;
|
||||
|
||||
// Don't use mime types manager if the application doesn't need it and it would be
|
||||
// cause an unacceptable delay, especially on startup.
|
||||
#if wxUSE_SYSTEM_OPTIONS
|
||||
if ( !wxSystemOptions::GetOptionInt(wxT("filesys.no-mimetypesmanager")) )
|
||||
#endif
|
||||
{
|
||||
if (!s_MinimalMimeEnsured)
|
||||
{
|
||||
static const wxFileTypeInfo fallbacks[] =
|
||||
{
|
||||
wxFileTypeInfo(wxT("image/jpeg"),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxT("JPEG image (from fallback)"),
|
||||
wxT("jpg"), wxT("jpeg"), wxT("JPG"), wxT("JPEG"), wxNullPtr),
|
||||
wxFileTypeInfo(wxT("image/gif"),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxT("GIF image (from fallback)"),
|
||||
wxT("gif"), wxT("GIF"), wxNullPtr),
|
||||
wxFileTypeInfo(wxT("image/png"),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxT("PNG image (from fallback)"),
|
||||
wxT("png"), wxT("PNG"), wxNullPtr),
|
||||
wxFileTypeInfo(wxT("image/bmp"),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxT("windows bitmap image (from fallback)"),
|
||||
wxT("bmp"), wxT("BMP"), wxNullPtr),
|
||||
wxFileTypeInfo(wxT("text/html"),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxT("HTML document (from fallback)"),
|
||||
wxT("htm"), wxT("html"), wxT("HTM"), wxT("HTML"), wxNullPtr),
|
||||
// must terminate the table with this!
|
||||
wxFileTypeInfo()
|
||||
};
|
||||
wxTheMimeTypesManager->AddFallbacks(fallbacks);
|
||||
s_MinimalMimeEnsured = true;
|
||||
}
|
||||
|
||||
wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
|
||||
if ( !ft || !ft -> GetMimeType(&mime) )
|
||||
{
|
||||
mime.clear();
|
||||
}
|
||||
|
||||
delete ft;
|
||||
|
||||
return mime;
|
||||
}
|
||||
#endif // wxUSE_MIMETYPE
|
||||
|
||||
// Without wxUSE_MIMETYPE, recognize just a few hardcoded special cases.
|
||||
if ( ext.IsSameAs(wxT("htm"), false) || ext.IsSameAs(wxT("html"), false) )
|
||||
return wxT("text/html");
|
||||
if ( ext.IsSameAs(wxT("jpg"), false) || ext.IsSameAs(wxT("jpeg"), false) )
|
||||
return wxT("image/jpeg");
|
||||
if ( ext.IsSameAs(wxT("gif"), false) )
|
||||
return wxT("image/gif");
|
||||
if ( ext.IsSameAs(wxT("png"), false) )
|
||||
return wxT("image/png");
|
||||
if ( ext.IsSameAs(wxT("bmp"), false) )
|
||||
return wxT("image/bmp");
|
||||
|
||||
return wxString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* static */
|
||||
wxString wxFileSystemHandler::GetProtocol(const wxString& location)
|
||||
{
|
||||
wxString s;
|
||||
int i, l = location.length();
|
||||
bool fnd = false;
|
||||
|
||||
for (i = l-1; (i >= 0) && ((location[i] != wxT('#')) || (!fnd)); i--) {
|
||||
if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true;
|
||||
}
|
||||
if (!fnd) return wxT("file");
|
||||
for (++i; (i < l) && (location[i] != wxT(':')); i++) s << location[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
wxString wxFileSystemHandler::GetLeftLocation(const wxString& location)
|
||||
{
|
||||
int i;
|
||||
bool fnd = false;
|
||||
|
||||
for (i = location.length()-1; i >= 0; i--) {
|
||||
if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true;
|
||||
else if (fnd && (location[i] == wxT('#'))) return location.Left(i);
|
||||
}
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxString wxFileSystemHandler::GetRightLocation(const wxString& location)
|
||||
{
|
||||
int i, len = location.length();
|
||||
for (i = len-1; i >= 0; i--)
|
||||
{
|
||||
if (location[i] == wxT('#'))
|
||||
len = i;
|
||||
if (location[i] != wxT(':'))
|
||||
continue;
|
||||
|
||||
// C: on Windows
|
||||
if (i == 1)
|
||||
continue;
|
||||
if (i >= 2 && wxIsalpha(location[i-1]) && location[i-2] == wxT('/'))
|
||||
continue;
|
||||
|
||||
// Could be the protocol
|
||||
break;
|
||||
}
|
||||
if (i == 0) return wxEmptyString;
|
||||
|
||||
const static wxString protocol(wxT("file:"));
|
||||
if (i < (int)protocol.length() - 1 || location.compare(0, i + 1, protocol))
|
||||
return location.Mid(i + 1, len - i - 1);
|
||||
|
||||
int s = ++i; // Start position
|
||||
// Check if there are three '/'s after "file:"
|
||||
int end = wxMin(len, s + 3);
|
||||
while (i < end && location[i] == wxT('/'))
|
||||
i++;
|
||||
if (i == s + 2) // Host is specified, e.g. "file://host/path"
|
||||
return location.Mid(s, len - s);
|
||||
if (i > s)
|
||||
{
|
||||
// Remove the last '/' if it is preceding "C:/...".
|
||||
// Otherwise, keep it.
|
||||
if (i + 1 >= len || location[i + 1] != wxT(':'))
|
||||
i--;
|
||||
else if (i + 4 < len)
|
||||
{
|
||||
// Check if ':' was encoded
|
||||
const static wxString colonLower(wxT("%3a"));
|
||||
const static wxString colonUpper(wxT("%3A"));
|
||||
wxString sub =location.Mid(i + 1, 3);
|
||||
if (sub == colonLower || sub == colonUpper)
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return location.Mid(i, len - i);
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxString wxFileSystemHandler::GetAnchor(const wxString& location)
|
||||
{
|
||||
int l = location.length();
|
||||
|
||||
for (int i = l-1; i >= 0; i--) {
|
||||
wxChar c;
|
||||
c = location[i];
|
||||
if (c == wxT('#'))
|
||||
return location.Right(l-i-1);
|
||||
else if ((c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':')))
|
||||
break;
|
||||
}
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
|
||||
wxString wxFileSystemHandler::FindFirst(const wxString& WXUNUSED(spec),
|
||||
int WXUNUSED(flags))
|
||||
{
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
wxString wxFileSystemHandler::FindNext()
|
||||
{
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// wxLocalFSHandler
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
wxString wxLocalFSHandler::ms_root;
|
||||
|
||||
bool wxLocalFSHandler::CanOpen(const wxString& location)
|
||||
{
|
||||
return GetProtocol(location) == wxT("file");
|
||||
}
|
||||
|
||||
wxFSFile* wxLocalFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location)
|
||||
{
|
||||
// location has Unix path separators
|
||||
wxString right = GetRightLocation(location);
|
||||
wxFileName fn = wxFileName::URLToFileName(right);
|
||||
wxString fullpath = ms_root + fn.GetFullPath();
|
||||
|
||||
if (!wxFileExists(fullpath))
|
||||
return NULL;
|
||||
|
||||
// we need to check whether we can really read from this file, otherwise
|
||||
// wxFSFile is not going to work
|
||||
#if wxUSE_FFILE
|
||||
wxFFileInputStream *is = new wxFFileInputStream(fullpath);
|
||||
#elif wxUSE_FILE
|
||||
wxFileInputStream *is = new wxFileInputStream(fullpath);
|
||||
#else
|
||||
#error One of wxUSE_FILE or wxUSE_FFILE must be set to 1 for wxFSHandler to work
|
||||
#endif
|
||||
if ( !is->IsOk() )
|
||||
{
|
||||
delete is;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new wxFSFile(is,
|
||||
location,
|
||||
wxEmptyString,
|
||||
GetAnchor(location)
|
||||
#if wxUSE_DATETIME
|
||||
,wxDateTime(wxFileModificationTime(fullpath))
|
||||
#endif // wxUSE_DATETIME
|
||||
);
|
||||
}
|
||||
|
||||
wxString wxLocalFSHandler::FindFirst(const wxString& spec, int flags)
|
||||
{
|
||||
wxFileName fn = wxFileName::URLToFileName(GetRightLocation(spec));
|
||||
const wxString found = wxFindFirstFile(ms_root + fn.GetFullPath(), flags);
|
||||
if ( found.empty() )
|
||||
return found;
|
||||
return wxFileSystem::FileNameToURL(found);
|
||||
}
|
||||
|
||||
wxString wxLocalFSHandler::FindNext()
|
||||
{
|
||||
const wxString found = wxFindNextFile();
|
||||
if ( found.empty() )
|
||||
return found;
|
||||
return wxFileSystem::FileNameToURL(found);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// wxFileSystem
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxFileSystem, wxObject);
|
||||
wxIMPLEMENT_ABSTRACT_CLASS(wxFSFile, wxObject);
|
||||
|
||||
|
||||
wxList wxFileSystem::m_Handlers;
|
||||
|
||||
|
||||
wxFileSystem::~wxFileSystem()
|
||||
{
|
||||
WX_CLEAR_HASH_MAP(wxFSHandlerHash, m_LocalHandlers)
|
||||
}
|
||||
|
||||
|
||||
static wxString MakeCorrectPath(const wxString& path)
|
||||
{
|
||||
wxString p(path);
|
||||
wxString r;
|
||||
int i, j, cnt;
|
||||
|
||||
cnt = p.length();
|
||||
for (i = 0; i < cnt; i++)
|
||||
if (p.GetChar(i) == wxT('\\')) p.GetWritableChar(i) = wxT('/'); // Want to be windows-safe
|
||||
|
||||
if (p.Left(2) == wxT("./")) { p = p.Mid(2); cnt -= 2; }
|
||||
|
||||
if (cnt < 3) return p;
|
||||
|
||||
r << p.GetChar(0) << p.GetChar(1);
|
||||
|
||||
// skip trailing ../.., if any
|
||||
for (i = 2; i < cnt && (p.GetChar(i) == wxT('/') || p.GetChar(i) == wxT('.')); i++) r << p.GetChar(i);
|
||||
|
||||
// remove back references: translate dir1/../dir2 to dir2
|
||||
for (; i < cnt; i++)
|
||||
{
|
||||
r << p.GetChar(i);
|
||||
if (p.GetChar(i) == wxT('/') && p.GetChar(i-1) == wxT('.') && p.GetChar(i-2) == wxT('.'))
|
||||
{
|
||||
for (j = r.length() - 2; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {}
|
||||
if (j >= 0 && r.GetChar(j) != wxT(':'))
|
||||
{
|
||||
for (j = j - 1; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {}
|
||||
r.Remove(j + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < cnt; i++) r << p.GetChar(i);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void wxFileSystem::ChangePathTo(const wxString& location, bool is_dir)
|
||||
{
|
||||
|
||||
m_Path = MakeCorrectPath(location);
|
||||
|
||||
if (is_dir)
|
||||
{
|
||||
if (!m_Path.empty() && m_Path.Last() != wxT('/') && m_Path.Last() != wxT(':'))
|
||||
m_Path << wxT('/');
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, pathpos = -1;
|
||||
for (i = m_Path.length()-1; i >= 0; i--)
|
||||
{
|
||||
if (m_Path[(unsigned int) i] == wxT('/'))
|
||||
{
|
||||
if ((i > 1) && (m_Path[(unsigned int) (i-1)] == wxT('/')) && (m_Path[(unsigned int) (i-2)] == wxT(':')))
|
||||
{
|
||||
i -= 2;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
pathpos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (m_Path[(unsigned int) i] == wxT(':')) {
|
||||
pathpos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pathpos == -1)
|
||||
{
|
||||
for (i = 0; i < (int) m_Path.length(); i++)
|
||||
{
|
||||
if (m_Path[(unsigned int) i] == wxT(':'))
|
||||
{
|
||||
m_Path.Remove(i+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == (int) m_Path.length())
|
||||
m_Path.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Path.Remove(pathpos+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
wxFileSystemHandler *wxFileSystem::MakeLocal(wxFileSystemHandler *h)
|
||||
{
|
||||
wxClassInfo *classinfo = h->GetClassInfo();
|
||||
|
||||
if (classinfo->IsDynamic())
|
||||
{
|
||||
wxFileSystemHandler*& local = m_LocalHandlers[classinfo];
|
||||
if (!local)
|
||||
local = (wxFileSystemHandler*)classinfo->CreateObject();
|
||||
return local;
|
||||
}
|
||||
else
|
||||
{
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
wxFSFile* wxFileSystem::OpenFile(const wxString& location, int flags)
|
||||
{
|
||||
if ((flags & wxFS_READ) == 0)
|
||||
return NULL;
|
||||
|
||||
wxString loc = MakeCorrectPath(location);
|
||||
unsigned i, ln;
|
||||
wxChar meta;
|
||||
wxFSFile *s = NULL;
|
||||
wxList::compatibility_iterator node;
|
||||
|
||||
ln = loc.length();
|
||||
meta = 0;
|
||||
for (i = 0; i < ln; i++)
|
||||
{
|
||||
switch ( loc[i].GetValue() )
|
||||
{
|
||||
case wxT('/') : case wxT(':') : case wxT('#') :
|
||||
meta = loc[i];
|
||||
break;
|
||||
}
|
||||
if (meta != 0) break;
|
||||
}
|
||||
m_LastName.clear();
|
||||
|
||||
// try relative paths first :
|
||||
if (meta != wxT(':'))
|
||||
{
|
||||
node = m_Handlers.GetFirst();
|
||||
while (node)
|
||||
{
|
||||
wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData();
|
||||
if (h->CanOpen(m_Path + loc))
|
||||
{
|
||||
s = MakeLocal(h)->OpenFile(*this, m_Path + loc);
|
||||
if (s) { m_LastName = m_Path + loc; break; }
|
||||
}
|
||||
node = node->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
// if failed, try absolute paths :
|
||||
if (s == NULL)
|
||||
{
|
||||
node = m_Handlers.GetFirst();
|
||||
while (node)
|
||||
{
|
||||
wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData();
|
||||
if (h->CanOpen(loc))
|
||||
{
|
||||
s = MakeLocal(h)->OpenFile(*this, loc);
|
||||
if (s) { m_LastName = loc; break; }
|
||||
}
|
||||
node = node->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
if (s && (flags & wxFS_SEEKABLE) != 0 && !s->GetStream()->IsSeekable())
|
||||
{
|
||||
wxBackedInputStream *stream;
|
||||
stream = new wxBackedInputStream(s->DetachStream());
|
||||
stream->FindLength();
|
||||
s->SetStream(stream);
|
||||
}
|
||||
|
||||
return (s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
wxString wxFileSystem::FindFirst(const wxString& spec, int flags)
|
||||
{
|
||||
wxList::compatibility_iterator node;
|
||||
wxString spec2(spec);
|
||||
|
||||
m_FindFileHandler = NULL;
|
||||
|
||||
for (int i = spec2.length()-1; i >= 0; i--)
|
||||
if (spec2[(unsigned int) i] == wxT('\\')) spec2.GetWritableChar(i) = wxT('/'); // Want to be windows-safe
|
||||
|
||||
node = m_Handlers.GetFirst();
|
||||
while (node)
|
||||
{
|
||||
wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData();
|
||||
if (h -> CanOpen(m_Path + spec2))
|
||||
{
|
||||
m_FindFileHandler = MakeLocal(h);
|
||||
return m_FindFileHandler -> FindFirst(m_Path + spec2, flags);
|
||||
}
|
||||
node = node->GetNext();
|
||||
}
|
||||
|
||||
node = m_Handlers.GetFirst();
|
||||
while (node)
|
||||
{
|
||||
wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData();
|
||||
if (h -> CanOpen(spec2))
|
||||
{
|
||||
m_FindFileHandler = MakeLocal(h);
|
||||
return m_FindFileHandler -> FindFirst(spec2, flags);
|
||||
}
|
||||
node = node->GetNext();
|
||||
}
|
||||
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
|
||||
|
||||
wxString wxFileSystem::FindNext()
|
||||
{
|
||||
if (m_FindFileHandler == NULL) return wxEmptyString;
|
||||
else return m_FindFileHandler -> FindNext();
|
||||
}
|
||||
|
||||
bool wxFileSystem::FindFileInPath(wxString *pStr,
|
||||
const wxString& path,
|
||||
const wxString& basename)
|
||||
{
|
||||
// we assume that it's not empty
|
||||
wxCHECK_MSG( !basename.empty(), false,
|
||||
wxT("empty file name in wxFileSystem::FindFileInPath"));
|
||||
|
||||
wxString name;
|
||||
// skip path separator in the beginning of the file name if present
|
||||
if ( wxIsPathSeparator(basename[0u]) )
|
||||
name = basename.substr(1);
|
||||
else
|
||||
name = basename;
|
||||
|
||||
wxStringTokenizer tokenizer(path, wxPATH_SEP);
|
||||
while ( tokenizer.HasMoreTokens() )
|
||||
{
|
||||
wxString strFile = tokenizer.GetNextToken();
|
||||
if ( !wxEndsWithPathSeparator(strFile) )
|
||||
strFile += wxFILE_SEP_PATH;
|
||||
strFile += name;
|
||||
|
||||
wxFSFile *file = OpenFile(strFile);
|
||||
if ( file )
|
||||
{
|
||||
delete file;
|
||||
*pStr = strFile;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxFileSystem::AddHandler(wxFileSystemHandler *handler)
|
||||
{
|
||||
// prepend the handler to the beginning of the list because handlers added
|
||||
// last should have the highest priority to allow overriding them
|
||||
m_Handlers.Insert((size_t)0, handler);
|
||||
}
|
||||
|
||||
wxFileSystemHandler* wxFileSystem::RemoveHandler(wxFileSystemHandler *handler)
|
||||
{
|
||||
// if handler has already been removed (or deleted)
|
||||
// we return NULL. This is by design in case
|
||||
// CleanUpHandlers() is called before RemoveHandler
|
||||
// is called, as we cannot control the order
|
||||
// which modules are unloaded
|
||||
if (!m_Handlers.DeleteObject(handler))
|
||||
return NULL;
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
|
||||
bool wxFileSystem::HasHandlerForPath(const wxString &location)
|
||||
{
|
||||
for ( wxList::compatibility_iterator node = m_Handlers.GetFirst();
|
||||
node; node = node->GetNext() )
|
||||
{
|
||||
wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData();
|
||||
if (h->CanOpen(location))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxFileSystem::CleanUpHandlers()
|
||||
{
|
||||
WX_CLEAR_LIST(wxList, m_Handlers);
|
||||
}
|
||||
|
||||
// Returns the native path for a file URL
|
||||
wxFileName wxFileSystem::URLToFileName(const wxString& url)
|
||||
{
|
||||
return wxFileName::URLToFileName( url );
|
||||
}
|
||||
|
||||
// Returns the file URL for a native path
|
||||
wxString wxFileSystem::FileNameToURL(const wxFileName& filename)
|
||||
{
|
||||
return wxFileName::FileNameToURL( filename );
|
||||
}
|
||||
|
||||
|
||||
///// Module:
|
||||
|
||||
class wxFileSystemModule : public wxModule
|
||||
{
|
||||
wxDECLARE_DYNAMIC_CLASS(wxFileSystemModule);
|
||||
|
||||
public:
|
||||
wxFileSystemModule() :
|
||||
wxModule(),
|
||||
m_handler(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool OnInit() wxOVERRIDE
|
||||
{
|
||||
m_handler = new wxLocalFSHandler;
|
||||
wxFileSystem::AddHandler(m_handler);
|
||||
return true;
|
||||
}
|
||||
virtual void OnExit() wxOVERRIDE
|
||||
{
|
||||
delete wxFileSystem::RemoveHandler(m_handler);
|
||||
|
||||
wxFileSystem::CleanUpHandlers();
|
||||
}
|
||||
|
||||
private:
|
||||
wxFileSystemHandler* m_handler;
|
||||
|
||||
};
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxFileSystemModule, wxModule);
|
||||
|
||||
//// wxFSInputStream
|
||||
|
||||
wxFSInputStream::wxFSInputStream(const wxString& filename, int flags)
|
||||
{
|
||||
wxFileSystem fs;
|
||||
m_file = fs.OpenFile(filename, flags | wxFS_READ);
|
||||
|
||||
if ( m_file )
|
||||
{
|
||||
wxInputStream* const stream = m_file->GetStream();
|
||||
if ( stream )
|
||||
{
|
||||
// Notice that we pass the stream by reference: it shouldn't be
|
||||
// deleted by us as it's owned by m_file already.
|
||||
InitParentStream(*stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxFSInputStream::~wxFSInputStream()
|
||||
{
|
||||
delete m_file;
|
||||
}
|
||||
|
||||
#endif
|
||||
// wxUSE_FILESYSTEM
|
||||
@@ -0,0 +1,32 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/filtall.cpp
|
||||
// Purpose: Link all filter streams
|
||||
// Author: Mike Wetherell
|
||||
// Copyright: (c) 2006 Mike Wetherell
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_STREAMS
|
||||
|
||||
#if wxUSE_ZLIB
|
||||
#include "wx/zstream.h"
|
||||
#endif
|
||||
|
||||
// Reference filter classes to ensure they are linked into a statically
|
||||
// linked program that uses Find or GetFirst to look for an filter handler.
|
||||
// It is in its own file so that the user can override this behaviour by
|
||||
// providing their own implementation.
|
||||
|
||||
void wxUseFilterClasses()
|
||||
{
|
||||
#if wxUSE_ZLIB
|
||||
wxZlibClassFactory();
|
||||
wxGzipClassFactory();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // wxUSE_STREAMS
|
||||
@@ -0,0 +1,39 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/filtfind.cpp
|
||||
// Purpose: Streams for filter formats
|
||||
// Author: Mike Wetherell
|
||||
// Copyright: (c) Mike Wetherell
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_STREAMS
|
||||
|
||||
#include "wx/stream.h"
|
||||
|
||||
// These functions are in a separate file so that statically linked apps
|
||||
// that do not call them to search for filter handlers will only link in
|
||||
// the filter classes they use.
|
||||
|
||||
const wxFilterClassFactory *
|
||||
wxFilterClassFactory::Find(const wxString& protocol, wxStreamProtocolType type)
|
||||
{
|
||||
for (const wxFilterClassFactory *f = GetFirst(); f; f = f->GetNext())
|
||||
if (f->CanHandle(protocol, type))
|
||||
return f;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// static
|
||||
const wxFilterClassFactory *wxFilterClassFactory::GetFirst()
|
||||
{
|
||||
if (!sm_first)
|
||||
wxUseFilterClasses();
|
||||
return sm_first;
|
||||
}
|
||||
|
||||
#endif // wxUSE_STREAMS
|
||||
@@ -0,0 +1,868 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/fmapbase.cpp
|
||||
// Purpose: wxFontMapperBase class implementation
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 21.06.2003 (extracted from common/fontmap.cpp)
|
||||
// Copyright: (c) 1999-2003 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_FONTMAP
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/app.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/module.h"
|
||||
#include "wx/wxcrtvararg.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
#include "wx/msw/private.h" // includes windows.h for LOGFONT
|
||||
#include "wx/msw/winundef.h"
|
||||
#endif
|
||||
|
||||
#include "wx/fontmap.h"
|
||||
#include "wx/fmappriv.h"
|
||||
|
||||
#include "wx/apptrait.h"
|
||||
|
||||
// wxMemoryConfig uses wxFileConfig
|
||||
#if wxUSE_CONFIG && wxUSE_FILECONFIG
|
||||
#include "wx/config.h"
|
||||
#include "wx/memconf.h"
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constants
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// encodings supported by GetEncodingDescription
|
||||
static const wxFontEncoding gs_encodings[] =
|
||||
{
|
||||
wxFONTENCODING_ISO8859_1,
|
||||
wxFONTENCODING_ISO8859_2,
|
||||
wxFONTENCODING_ISO8859_3,
|
||||
wxFONTENCODING_ISO8859_4,
|
||||
wxFONTENCODING_ISO8859_5,
|
||||
wxFONTENCODING_ISO8859_6,
|
||||
wxFONTENCODING_ISO8859_7,
|
||||
wxFONTENCODING_ISO8859_8,
|
||||
wxFONTENCODING_ISO8859_9,
|
||||
wxFONTENCODING_ISO8859_10,
|
||||
wxFONTENCODING_ISO8859_11,
|
||||
wxFONTENCODING_ISO8859_12,
|
||||
wxFONTENCODING_ISO8859_13,
|
||||
wxFONTENCODING_ISO8859_14,
|
||||
wxFONTENCODING_ISO8859_15,
|
||||
wxFONTENCODING_KOI8,
|
||||
wxFONTENCODING_KOI8_U,
|
||||
wxFONTENCODING_CP866,
|
||||
wxFONTENCODING_CP874,
|
||||
wxFONTENCODING_CP932,
|
||||
wxFONTENCODING_CP936,
|
||||
wxFONTENCODING_CP949,
|
||||
wxFONTENCODING_CP950,
|
||||
wxFONTENCODING_CP1250,
|
||||
wxFONTENCODING_CP1251,
|
||||
wxFONTENCODING_CP1252,
|
||||
wxFONTENCODING_CP1253,
|
||||
wxFONTENCODING_CP1254,
|
||||
wxFONTENCODING_CP1255,
|
||||
wxFONTENCODING_CP1256,
|
||||
wxFONTENCODING_CP1257,
|
||||
wxFONTENCODING_CP1258,
|
||||
wxFONTENCODING_CP1361,
|
||||
wxFONTENCODING_CP437,
|
||||
wxFONTENCODING_UTF7,
|
||||
wxFONTENCODING_UTF8,
|
||||
wxFONTENCODING_UTF16BE,
|
||||
wxFONTENCODING_UTF16LE,
|
||||
wxFONTENCODING_UTF32BE,
|
||||
wxFONTENCODING_UTF32LE,
|
||||
wxFONTENCODING_EUC_JP,
|
||||
wxFONTENCODING_DEFAULT,
|
||||
wxFONTENCODING_ISO2022_JP,
|
||||
|
||||
wxFONTENCODING_MACROMAN,
|
||||
wxFONTENCODING_MACJAPANESE,
|
||||
wxFONTENCODING_MACCHINESETRAD,
|
||||
wxFONTENCODING_MACKOREAN,
|
||||
wxFONTENCODING_MACARABIC,
|
||||
wxFONTENCODING_MACHEBREW,
|
||||
wxFONTENCODING_MACGREEK,
|
||||
wxFONTENCODING_MACCYRILLIC,
|
||||
wxFONTENCODING_MACDEVANAGARI,
|
||||
wxFONTENCODING_MACGURMUKHI,
|
||||
wxFONTENCODING_MACGUJARATI,
|
||||
wxFONTENCODING_MACORIYA,
|
||||
wxFONTENCODING_MACBENGALI,
|
||||
wxFONTENCODING_MACTAMIL,
|
||||
wxFONTENCODING_MACTELUGU,
|
||||
wxFONTENCODING_MACKANNADA,
|
||||
wxFONTENCODING_MACMALAJALAM,
|
||||
wxFONTENCODING_MACSINHALESE,
|
||||
wxFONTENCODING_MACBURMESE,
|
||||
wxFONTENCODING_MACKHMER,
|
||||
wxFONTENCODING_MACTHAI,
|
||||
wxFONTENCODING_MACLAOTIAN,
|
||||
wxFONTENCODING_MACGEORGIAN,
|
||||
wxFONTENCODING_MACARMENIAN,
|
||||
wxFONTENCODING_MACCHINESESIMP,
|
||||
wxFONTENCODING_MACTIBETAN,
|
||||
wxFONTENCODING_MACMONGOLIAN,
|
||||
wxFONTENCODING_MACETHIOPIC,
|
||||
wxFONTENCODING_MACCENTRALEUR,
|
||||
wxFONTENCODING_MACVIATNAMESE,
|
||||
wxFONTENCODING_MACARABICEXT,
|
||||
wxFONTENCODING_MACSYMBOL,
|
||||
wxFONTENCODING_MACDINGBATS,
|
||||
wxFONTENCODING_MACTURKISH,
|
||||
wxFONTENCODING_MACCROATIAN,
|
||||
wxFONTENCODING_MACICELANDIC,
|
||||
wxFONTENCODING_MACROMANIAN,
|
||||
wxFONTENCODING_MACCELTIC,
|
||||
wxFONTENCODING_MACGAELIC,
|
||||
wxFONTENCODING_MACKEYBOARD
|
||||
};
|
||||
|
||||
// the descriptions for them
|
||||
static const char* const gs_encodingDescs[] =
|
||||
{
|
||||
wxTRANSLATE( "Western European (ISO-8859-1)" ),
|
||||
wxTRANSLATE( "Central European (ISO-8859-2)" ),
|
||||
wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
|
||||
wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ),
|
||||
wxTRANSLATE( "Cyrillic (ISO-8859-5)" ),
|
||||
wxTRANSLATE( "Arabic (ISO-8859-6)" ),
|
||||
wxTRANSLATE( "Greek (ISO-8859-7)" ),
|
||||
wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
|
||||
wxTRANSLATE( "Turkish (ISO-8859-9)" ),
|
||||
wxTRANSLATE( "Nordic (ISO-8859-10)" ),
|
||||
wxTRANSLATE( "Thai (ISO-8859-11)" ),
|
||||
wxTRANSLATE( "Indian (ISO-8859-12)" ),
|
||||
wxTRANSLATE( "Baltic (ISO-8859-13)" ),
|
||||
wxTRANSLATE( "Celtic (ISO-8859-14)" ),
|
||||
wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ),
|
||||
wxTRANSLATE( "KOI8-R" ),
|
||||
wxTRANSLATE( "KOI8-U" ),
|
||||
wxTRANSLATE( "Windows/DOS OEM Cyrillic (CP 866)" ),
|
||||
wxTRANSLATE( "Windows Thai (CP 874)" ),
|
||||
wxTRANSLATE( "Windows Japanese (CP 932) or Shift-JIS" ),
|
||||
wxTRANSLATE( "Windows Chinese Simplified (CP 936) or GB-2312" ),
|
||||
wxTRANSLATE( "Windows Korean (CP 949)" ),
|
||||
wxTRANSLATE( "Windows Chinese Traditional (CP 950) or Big-5" ),
|
||||
wxTRANSLATE( "Windows Central European (CP 1250)" ),
|
||||
wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
|
||||
wxTRANSLATE( "Windows Western European (CP 1252)" ),
|
||||
wxTRANSLATE( "Windows Greek (CP 1253)" ),
|
||||
wxTRANSLATE( "Windows Turkish (CP 1254)" ),
|
||||
wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
|
||||
wxTRANSLATE( "Windows Arabic (CP 1256)" ),
|
||||
wxTRANSLATE( "Windows Baltic (CP 1257)" ),
|
||||
wxTRANSLATE( "Windows Vietnamese (CP 1258)" ),
|
||||
wxTRANSLATE( "Windows Johab (CP 1361)" ),
|
||||
wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
|
||||
wxTRANSLATE( "Unicode 7 bit (UTF-7)" ),
|
||||
wxTRANSLATE( "Unicode 8 bit (UTF-8)" ),
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
wxTRANSLATE( "Unicode 16 bit (UTF-16)" ),
|
||||
wxTRANSLATE( "Unicode 16 bit Little Endian (UTF-16LE)" ),
|
||||
wxTRANSLATE( "Unicode 32 bit (UTF-32)" ),
|
||||
wxTRANSLATE( "Unicode 32 bit Little Endian (UTF-32LE)" ),
|
||||
#else // WORDS_BIGENDIAN
|
||||
wxTRANSLATE( "Unicode 16 bit Big Endian (UTF-16BE)" ),
|
||||
wxTRANSLATE( "Unicode 16 bit (UTF-16)" ),
|
||||
wxTRANSLATE( "Unicode 32 bit Big Endian (UTF-32BE)" ),
|
||||
wxTRANSLATE( "Unicode 32 bit (UTF-32)" ),
|
||||
#endif // WORDS_BIGENDIAN
|
||||
wxTRANSLATE( "Extended Unix Codepage for Japanese (EUC-JP)" ),
|
||||
wxTRANSLATE( "US-ASCII" ),
|
||||
wxTRANSLATE( "ISO-2022-JP" ),
|
||||
|
||||
wxTRANSLATE( "MacRoman" ),
|
||||
wxTRANSLATE( "MacJapanese" ),
|
||||
wxTRANSLATE( "MacChineseTrad" ),
|
||||
wxTRANSLATE( "MacKorean" ),
|
||||
wxTRANSLATE( "MacArabic" ),
|
||||
wxTRANSLATE( "MacHebrew" ),
|
||||
wxTRANSLATE( "MacGreek" ),
|
||||
wxTRANSLATE( "MacCyrillic" ),
|
||||
wxTRANSLATE( "MacDevanagari" ),
|
||||
wxTRANSLATE( "MacGurmukhi" ),
|
||||
wxTRANSLATE( "MacGujarati" ),
|
||||
wxTRANSLATE( "MacOriya" ),
|
||||
wxTRANSLATE( "MacBengali" ),
|
||||
wxTRANSLATE( "MacTamil" ),
|
||||
wxTRANSLATE( "MacTelugu" ),
|
||||
wxTRANSLATE( "MacKannada" ),
|
||||
wxTRANSLATE( "MacMalayalam" ),
|
||||
wxTRANSLATE( "MacSinhalese" ),
|
||||
wxTRANSLATE( "MacBurmese" ),
|
||||
wxTRANSLATE( "MacKhmer" ),
|
||||
wxTRANSLATE( "MacThai" ),
|
||||
wxTRANSLATE( "MacLaotian" ),
|
||||
wxTRANSLATE( "MacGeorgian" ),
|
||||
wxTRANSLATE( "MacArmenian" ),
|
||||
wxTRANSLATE( "MacChineseSimp" ),
|
||||
wxTRANSLATE( "MacTibetan" ),
|
||||
wxTRANSLATE( "MacMongolian" ),
|
||||
wxTRANSLATE( "MacEthiopic" ),
|
||||
wxTRANSLATE( "MacCentralEurRoman" ),
|
||||
wxTRANSLATE( "MacVietnamese" ),
|
||||
wxTRANSLATE( "MacExtArabic" ),
|
||||
wxTRANSLATE( "MacSymbol" ),
|
||||
wxTRANSLATE( "MacDingbats" ),
|
||||
wxTRANSLATE( "MacTurkish" ),
|
||||
wxTRANSLATE( "MacCroatian" ),
|
||||
wxTRANSLATE( "MacIcelandic" ),
|
||||
wxTRANSLATE( "MacRomanian" ),
|
||||
wxTRANSLATE( "MacCeltic" ),
|
||||
wxTRANSLATE( "MacGaelic" ),
|
||||
wxTRANSLATE( "MacKeyboardGlyphs" )
|
||||
};
|
||||
|
||||
// and the internal names (these are not translated on purpose!)
|
||||
static const wxChar* const gs_encodingNames[][9] =
|
||||
{
|
||||
// names from the columns correspond to these OS:
|
||||
// Linux Solaris and IRIX HP-UX AIX
|
||||
{ wxT("ISO-8859-1"), wxT("ISO8859-1"), wxT("iso88591"), wxT("8859-1"), wxT("iso_8859_1"), NULL },
|
||||
{ wxT("ISO-8859-2"), wxT("ISO8859-2"), wxT("iso88592"), wxT("8859-2"), NULL },
|
||||
{ wxT("ISO-8859-3"), wxT("ISO8859-3"), wxT("iso88593"), wxT("8859-3"), NULL },
|
||||
{ wxT("ISO-8859-4"), wxT("ISO8859-4"), wxT("iso88594"), wxT("8859-4"), NULL },
|
||||
{ wxT("ISO-8859-5"), wxT("ISO8859-5"), wxT("iso88595"), wxT("8859-5"), NULL },
|
||||
{ wxT("ISO-8859-6"), wxT("ISO8859-6"), wxT("iso88596"), wxT("8859-6"), NULL },
|
||||
{ wxT("ISO-8859-7"), wxT("ISO8859-7"), wxT("iso88597"), wxT("8859-7"), NULL },
|
||||
{ wxT("ISO-8859-8"), wxT("ISO8859-8"), wxT("iso88598"), wxT("8859-8"), NULL },
|
||||
{ wxT("ISO-8859-9"), wxT("ISO8859-9"), wxT("iso88599"), wxT("8859-9"), NULL },
|
||||
{ wxT("ISO-8859-10"), wxT("ISO8859-10"), wxT("iso885910"), wxT("8859-10"), NULL },
|
||||
{ wxT("ISO-8859-11"), wxT("ISO8859-11"), wxT("iso885911"), wxT("8859-11"), NULL },
|
||||
{ wxT("ISO-8859-12"), wxT("ISO8859-12"), wxT("iso885912"), wxT("8859-12"), NULL },
|
||||
{ wxT("ISO-8859-13"), wxT("ISO8859-13"), wxT("iso885913"), wxT("8859-13"), NULL },
|
||||
{ wxT("ISO-8859-14"), wxT("ISO8859-14"), wxT("iso885914"), wxT("8859-14"), NULL },
|
||||
{ wxT("ISO-8859-15"), wxT("ISO8859-15"), wxT("iso885915"), wxT("8859-15"), NULL },
|
||||
|
||||
// although koi8-ru is not strictly speaking the same as koi8-r,
|
||||
// they are similar enough to make mapping it to koi8 better than
|
||||
// not recognizing it at all
|
||||
{ wxT( "KOI8-R" ), wxT( "KOI8-RU" ), NULL },
|
||||
{ wxT( "KOI8-U" ), NULL },
|
||||
|
||||
{ wxT( "WINDOWS-866" ), wxT( "CP866" ), NULL },
|
||||
|
||||
{ wxT( "WINDOWS-874" ), wxT( "CP874" ), wxT( "MS874" ), wxT( "IBM-874" ), NULL },
|
||||
{ wxT( "WINDOWS-932" ), wxT( "CP932" ), wxT( "MS932" ), wxT( "IBM-932" ), wxT( "SJIS" ), wxT( "SHIFT-JIS" ), wxT( "SHIFT_JIS" ), NULL },
|
||||
{ wxT( "WINDOWS-936" ), wxT( "CP936" ), wxT( "MS936" ), wxT( "IBM-936" ), wxT( "GB2312" ), wxT( "gbk" ),wxT( "GBK" ), NULL },
|
||||
{ wxT( "WINDOWS-949" ), wxT( "CP949" ), wxT( "MS949" ), wxT( "IBM-949" ), wxT( "EUC-KR" ), wxT( "eucKR" ), wxT( "euc_kr" ), NULL },
|
||||
{ wxT( "WINDOWS-950" ), wxT( "CP950" ), wxT( "MS950" ), wxT( "IBM-950" ), wxT( "BIG5" ), wxT( "BIG-5" ), wxT( "BIG-FIVE" ), NULL },
|
||||
{ wxT( "WINDOWS-1250" ),wxT( "CP1250" ),wxT( "MS1250" ),wxT( "IBM-1250" ),NULL },
|
||||
{ wxT( "WINDOWS-1251" ),wxT( "CP1251" ),wxT( "MS1251" ),wxT( "IBM-1251" ),NULL },
|
||||
{ wxT( "WINDOWS-1252" ),wxT( "CP1252" ),wxT( "MS1252" ),wxT( "IBM-1252" ),NULL },
|
||||
{ wxT( "WINDOWS-1253" ),wxT( "CP1253" ),wxT( "MS1253" ),wxT( "IBM-1253" ),NULL },
|
||||
{ wxT( "WINDOWS-1254" ),wxT( "CP1254" ),wxT( "MS1254" ),wxT( "IBM-1254" ),NULL },
|
||||
{ wxT( "WINDOWS-1255" ),wxT( "CP1255" ),wxT( "MS1255" ),wxT( "IBM-1255" ),NULL },
|
||||
{ wxT( "WINDOWS-1256" ),wxT( "CP1256" ),wxT( "MS1256" ),wxT( "IBM-1256" ),NULL },
|
||||
{ wxT( "WINDOWS-1257" ),wxT( "CP1257" ),wxT( "MS1257" ),wxT( "IBM-1257" ),NULL },
|
||||
{ wxT( "WINDOWS-1258" ),wxT( "CP1258" ),wxT( "MS1258" ),wxT( "IBM-1258" ),NULL },
|
||||
{ wxT( "WINDOWS-1361" ),wxT( "CP1361" ),wxT( "MS1361" ),wxT( "IBM-1361" ), wxT( "JOHAB" ), NULL },
|
||||
{ wxT( "WINDOWS-437" ), wxT( "CP437" ), wxT( "MS437" ), wxT( "IBM-437" ), NULL },
|
||||
|
||||
{ wxT( "UTF-7" ), wxT("UTF7"), NULL },
|
||||
{ wxT( "UTF-8" ), wxT("UTF8"), NULL },
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
{ wxT( "UTF-16BE" ), wxT("UTF16BE"), wxT("UCS-2BE"), wxT("UCS2BE"), wxT("UTF-16"), wxT("UTF16"), wxT("UCS-2"), wxT("UCS2"), NULL },
|
||||
{ wxT( "UTF-16LE" ), wxT("UTF16LE"), wxT("UCS-2LE"), wxT("UCS2LE"), NULL },
|
||||
{ wxT( "UTF-32BE" ), wxT("UTF32BE"), wxT("UCS-4BE" ), wxT("UTF-32"), wxT("UTF32"), wxT("UCS-4"), wxT("UCS4"), NULL },
|
||||
{ wxT( "UTF-32LE" ), wxT("UTF32LE"), wxT("UCS-4LE"), wxT("UCS4LE"), NULL },
|
||||
#else // WORDS_BIGENDIAN
|
||||
{ wxT("UTF-16BE"), wxT("UTF16BE"), wxT("UCS-2BE"), wxT("UCS2BE"), NULL },
|
||||
{ wxT("UTF-16LE"), wxT("UTF16LE"), wxT("UCS-2LE"), wxT("UTF-16"), wxT("UTF16"), wxT("UCS-2"), wxT("UCS2"), NULL },
|
||||
{ wxT("UTF-32BE"), wxT("UTF32BE"), wxT("UCS-4BE"), wxT("UCS4BE"), NULL },
|
||||
{ wxT("UTF-32LE"), wxT("UTF32LE"), wxT("UCS-4LE"), wxT("UCS4LE"), wxT("UTF-32"), wxT("UTF32"), wxT("UCS-4"), wxT("UCS4"), NULL },
|
||||
#endif // WORDS_BIGENDIAN
|
||||
|
||||
{ wxT( "EUC-JP" ), wxT( "eucJP" ), wxT( "euc_jp" ), wxT( "IBM-eucJP" ), NULL },
|
||||
|
||||
// 646 is for Solaris, roman8 -- for HP-UX
|
||||
{ wxT( "US-ASCII" ), wxT( "ASCII" ), wxT("C"), wxT("POSIX"), wxT("ANSI_X3.4-1968"),
|
||||
wxT("646"), wxT("roman8"), wxT( "" ), NULL },
|
||||
|
||||
{ wxT( "ISO-2022-JP" ), NULL },
|
||||
|
||||
|
||||
{ wxT( "MacRoman" ), NULL },
|
||||
{ wxT( "MacJapanese" ), NULL },
|
||||
{ wxT( "MacChineseTrad" ), NULL },
|
||||
{ wxT( "MacKorean" ), NULL },
|
||||
{ wxT( "MacArabic" ), NULL },
|
||||
{ wxT( "MacHebrew" ), NULL },
|
||||
{ wxT( "MacGreek" ), NULL },
|
||||
{ wxT( "MacCyrillic" ), NULL },
|
||||
{ wxT( "MacDevanagari" ), NULL },
|
||||
{ wxT( "MacGurmukhi" ), NULL },
|
||||
{ wxT( "MacGujarati" ), NULL },
|
||||
{ wxT( "MacOriya" ), NULL },
|
||||
{ wxT( "MacBengali" ), NULL },
|
||||
{ wxT( "MacTamil" ), NULL },
|
||||
{ wxT( "MacTelugu" ), NULL },
|
||||
{ wxT( "MacKannada" ), NULL },
|
||||
{ wxT( "MacMalayalam" ), NULL },
|
||||
{ wxT( "MacSinhalese" ), NULL },
|
||||
{ wxT( "MacBurmese" ), NULL },
|
||||
{ wxT( "MacKhmer" ), NULL },
|
||||
{ wxT( "MacThai" ), NULL },
|
||||
{ wxT( "MacLaotian" ), NULL },
|
||||
{ wxT( "MacGeorgian" ), NULL },
|
||||
{ wxT( "MacArmenian" ), NULL },
|
||||
{ wxT( "MacChineseSimp" ), NULL },
|
||||
{ wxT( "MacTibetan" ), NULL },
|
||||
{ wxT( "MacMongolian" ), NULL },
|
||||
{ wxT( "MacEthiopic" ), NULL },
|
||||
{ wxT( "MacCentralEurRoman" ), NULL },
|
||||
{ wxT( "MacVietnamese" ), NULL },
|
||||
{ wxT( "MacExtArabic" ), NULL },
|
||||
{ wxT( "MacSymbol" ), NULL },
|
||||
{ wxT( "MacDingbats" ), NULL },
|
||||
{ wxT( "MacTurkish" ), NULL },
|
||||
{ wxT( "MacCroatian" ), NULL },
|
||||
{ wxT( "MacIcelandic" ), NULL },
|
||||
{ wxT( "MacRomanian" ), NULL },
|
||||
{ wxT( "MacCeltic" ), NULL },
|
||||
{ wxT( "MacGaelic" ), NULL },
|
||||
{ wxT( "MacKeyboardGlyphs" ), NULL }
|
||||
};
|
||||
|
||||
wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingDescs) == WXSIZEOF(gs_encodings), EncodingsArraysNotInSync );
|
||||
wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingNames) == WXSIZEOF(gs_encodings), EncodingsArraysNotInSync );
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// private classes
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// clean up the font mapper object
|
||||
class wxFontMapperModule : public wxModule
|
||||
{
|
||||
public:
|
||||
wxFontMapperModule() : wxModule() { }
|
||||
|
||||
virtual bool OnInit() wxOVERRIDE
|
||||
{
|
||||
// a dummy wxFontMapperBase object could have been created during the
|
||||
// program startup before wxApp was created, we have to delete it to
|
||||
// allow creating the real font mapper next time it is needed now that
|
||||
// we can create it (when the modules are initialized, wxApp object
|
||||
// already exists)
|
||||
wxFontMapperBase *fm = wxFontMapperBase::Get();
|
||||
if ( fm && fm->IsDummy() )
|
||||
wxFontMapperBase::Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void OnExit() wxOVERRIDE
|
||||
{
|
||||
wxFontMapperBase::Reset();
|
||||
}
|
||||
|
||||
wxDECLARE_DYNAMIC_CLASS(wxFontMapperModule);
|
||||
};
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// wxFontMapperBase implementation
|
||||
// ============================================================================
|
||||
|
||||
wxFontMapper *wxFontMapperBase::sm_instance = NULL;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ctor and dtor
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxFontMapperBase::wxFontMapperBase()
|
||||
{
|
||||
#if wxUSE_CONFIG && wxUSE_FILECONFIG
|
||||
m_configDummy = NULL;
|
||||
#endif // wxUSE_CONFIG
|
||||
}
|
||||
|
||||
wxFontMapperBase::~wxFontMapperBase()
|
||||
{
|
||||
#if wxUSE_CONFIG && wxUSE_FILECONFIG
|
||||
delete m_configDummy;
|
||||
#endif // wxUSE_CONFIG
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxFontMapperBase *wxFontMapperBase::Get()
|
||||
{
|
||||
if ( !sm_instance )
|
||||
{
|
||||
wxAppTraits *traits = wxApp::GetTraitsIfExists();
|
||||
if ( traits )
|
||||
{
|
||||
sm_instance = traits->CreateFontMapper();
|
||||
|
||||
wxASSERT_MSG( sm_instance,
|
||||
wxT("wxAppTraits::CreateFontMapper() failed") );
|
||||
}
|
||||
|
||||
if ( !sm_instance )
|
||||
{
|
||||
// last resort: we must create something because the existing code
|
||||
// relies on always having a valid font mapper object
|
||||
sm_instance = (wxFontMapper *)new wxFontMapperBase;
|
||||
}
|
||||
}
|
||||
|
||||
return (wxFontMapperBase*)sm_instance;
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxFontMapper *wxFontMapperBase::Set(wxFontMapper *mapper)
|
||||
{
|
||||
wxFontMapper *old = sm_instance;
|
||||
sm_instance = mapper;
|
||||
return old;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void wxFontMapperBase::Reset()
|
||||
{
|
||||
if ( sm_instance )
|
||||
{
|
||||
// we need a cast as wxFontMapper is not fully declared here and so the
|
||||
// compiler can't know that it derives from wxFontMapperBase (but
|
||||
// run-time behaviour will be correct because the dtor is virtual)
|
||||
delete (wxFontMapperBase *)sm_instance;
|
||||
sm_instance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if wxUSE_CONFIG && wxUSE_FILECONFIG
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// config usage customisation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
static wxString gs_defaultConfigPath(FONTMAPPER_ROOT_PATH);
|
||||
|
||||
/* static */
|
||||
const wxString& wxFontMapperBase::GetDefaultConfigPath()
|
||||
{
|
||||
// NB: we return const wxString& and not wxString for compatibility
|
||||
// with 2.8 that returned const wxChar*
|
||||
return gs_defaultConfigPath;
|
||||
}
|
||||
|
||||
void wxFontMapperBase::SetConfigPath(const wxString& prefix)
|
||||
{
|
||||
wxCHECK_RET( !prefix.empty() && prefix[0] == wxCONFIG_PATH_SEPARATOR,
|
||||
wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") );
|
||||
|
||||
m_configRootPath = prefix;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// get config object and path for it
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxConfigBase *wxFontMapperBase::GetConfig()
|
||||
{
|
||||
wxConfigBase *config = wxConfig::Get(false);
|
||||
|
||||
// If there is no global configuration, use an internal memory configuration
|
||||
if ( !config )
|
||||
{
|
||||
if ( !m_configDummy )
|
||||
m_configDummy = new wxMemoryConfig;
|
||||
config = m_configDummy;
|
||||
|
||||
// FIXME: ideally, we should add keys from dummy config to a real one later,
|
||||
// but it is a low-priority task because typical wxWin application
|
||||
// either doesn't use wxConfig at all or creates wxConfig object in
|
||||
// wxApp::OnInit(), before any real interaction with the user takes
|
||||
// place...
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
const wxString& wxFontMapperBase::GetConfigPath()
|
||||
{
|
||||
if ( !m_configRootPath )
|
||||
{
|
||||
// use the default
|
||||
m_configRootPath = GetDefaultConfigPath();
|
||||
}
|
||||
|
||||
return m_configRootPath;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// config helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxFontMapperBase::ChangePath(const wxString& pathNew, wxString *pathOld)
|
||||
{
|
||||
wxConfigBase *config = GetConfig();
|
||||
if ( !config )
|
||||
return false;
|
||||
|
||||
*pathOld = config->GetPath();
|
||||
|
||||
wxString path = GetConfigPath();
|
||||
if ( path.empty() || path.Last() != wxCONFIG_PATH_SEPARATOR )
|
||||
{
|
||||
path += wxCONFIG_PATH_SEPARATOR;
|
||||
}
|
||||
|
||||
wxASSERT_MSG( !pathNew || (pathNew[0] != wxCONFIG_PATH_SEPARATOR),
|
||||
wxT("should be a relative path") );
|
||||
|
||||
path += pathNew;
|
||||
|
||||
config->SetPath(path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxFontMapperBase::RestorePath(const wxString& pathOld)
|
||||
{
|
||||
GetConfig()->SetPath(pathOld);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// charset/encoding correspondence
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxFontEncoding
|
||||
wxFontMapperBase::CharsetToEncoding(const wxString& charset,
|
||||
bool WXUNUSED(interactive))
|
||||
{
|
||||
int enc = NonInteractiveCharsetToEncoding(charset);
|
||||
if ( enc == wxFONTENCODING_UNKNOWN )
|
||||
{
|
||||
// we should return wxFONTENCODING_SYSTEM from here for unknown
|
||||
// encodings
|
||||
enc = wxFONTENCODING_SYSTEM;
|
||||
}
|
||||
|
||||
return (wxFontEncoding)enc;
|
||||
}
|
||||
|
||||
int
|
||||
wxFontMapperBase::NonInteractiveCharsetToEncoding(const wxString& charset)
|
||||
{
|
||||
wxFontEncoding encoding = wxFONTENCODING_SYSTEM;
|
||||
|
||||
// we're going to modify it, make a copy
|
||||
wxString cs = charset;
|
||||
|
||||
#if wxUSE_CONFIG && wxUSE_FILECONFIG
|
||||
// first try the user-defined settings
|
||||
wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH);
|
||||
if ( path.IsOk() )
|
||||
{
|
||||
wxConfigBase *config = GetConfig();
|
||||
|
||||
// do we have an encoding for this charset?
|
||||
long value = config->Read(charset, -1l);
|
||||
if ( value != -1 )
|
||||
{
|
||||
if ( value == wxFONTENCODING_UNKNOWN )
|
||||
{
|
||||
// don't try to find it, in particular don't ask the user
|
||||
return value;
|
||||
}
|
||||
|
||||
if ( value >= 0 && value <= wxFONTENCODING_MAX )
|
||||
{
|
||||
encoding = (wxFontEncoding)value;
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"),
|
||||
value, charset.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if ( encoding == wxFONTENCODING_SYSTEM )
|
||||
{
|
||||
// may be we have an alias?
|
||||
config->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH);
|
||||
|
||||
wxString alias = config->Read(charset);
|
||||
if ( !alias.empty() )
|
||||
{
|
||||
// yes, we do - use it instead
|
||||
cs = alias;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // wxUSE_CONFIG
|
||||
|
||||
// if didn't find it there, try to recognize it ourselves
|
||||
if ( encoding == wxFONTENCODING_SYSTEM )
|
||||
{
|
||||
// trim any spaces
|
||||
cs.Trim(true);
|
||||
cs.Trim(false);
|
||||
|
||||
// discard the optional quotes
|
||||
if ( !cs.empty() )
|
||||
{
|
||||
if ( cs[0u] == wxT('"') && cs.Last() == wxT('"') )
|
||||
{
|
||||
cs = wxString(cs.c_str(), cs.length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
for ( size_t i = 0; i < WXSIZEOF(gs_encodingNames); ++i )
|
||||
{
|
||||
for ( const wxChar* const* encName = gs_encodingNames[i]; *encName; ++encName )
|
||||
{
|
||||
if ( cs.CmpNoCase(*encName) == 0 )
|
||||
return gs_encodings[i];
|
||||
}
|
||||
}
|
||||
|
||||
cs.MakeUpper();
|
||||
|
||||
if ( cs.Left(3) == wxT("ISO") )
|
||||
{
|
||||
// the dash is optional (or, to be exact, it is not, but
|
||||
// several broken programs "forget" it)
|
||||
const wxChar *p = cs.c_str() + 3;
|
||||
if ( *p == wxT('-') )
|
||||
p++;
|
||||
|
||||
unsigned int value;
|
||||
if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
|
||||
{
|
||||
// make it 0 based and check that it is strictly positive in
|
||||
// the process (no such thing as iso8859-0 encoding)
|
||||
if ( (value-- > 0) &&
|
||||
(value < wxFONTENCODING_ISO8859_MAX -
|
||||
wxFONTENCODING_ISO8859_1) )
|
||||
{
|
||||
// it's a valid ISO8859 encoding
|
||||
value += wxFONTENCODING_ISO8859_1;
|
||||
encoding = (wxFontEncoding)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( cs.Left(4) == wxT("8859") )
|
||||
{
|
||||
const wxChar *p = cs.c_str();
|
||||
|
||||
unsigned int value;
|
||||
if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
|
||||
{
|
||||
// make it 0 based and check that it is strictly positive in
|
||||
// the process (no such thing as iso8859-0 encoding)
|
||||
if ( (value-- > 0) &&
|
||||
(value < wxFONTENCODING_ISO8859_MAX -
|
||||
wxFONTENCODING_ISO8859_1) )
|
||||
{
|
||||
// it's a valid ISO8859 encoding
|
||||
value += wxFONTENCODING_ISO8859_1;
|
||||
encoding = (wxFontEncoding)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // check for Windows charsets
|
||||
{
|
||||
size_t len;
|
||||
if ( cs.Left(7) == wxT("WINDOWS") )
|
||||
{
|
||||
len = 7;
|
||||
}
|
||||
else if ( cs.Left(2) == wxT("CP") )
|
||||
{
|
||||
len = 2;
|
||||
}
|
||||
else // not a Windows encoding
|
||||
{
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if ( len )
|
||||
{
|
||||
const wxChar *p = cs.c_str() + len;
|
||||
if ( *p == wxT('-') )
|
||||
p++;
|
||||
|
||||
unsigned int value;
|
||||
if ( wxSscanf(p, wxT("%u"), &value) == 1 )
|
||||
{
|
||||
if ( value >= 1250 )
|
||||
{
|
||||
value -= 1250;
|
||||
if ( value < wxFONTENCODING_CP12_MAX -
|
||||
wxFONTENCODING_CP1250 )
|
||||
{
|
||||
// a valid Windows code page
|
||||
value += wxFONTENCODING_CP1250;
|
||||
encoding = (wxFontEncoding)value;
|
||||
}
|
||||
}
|
||||
|
||||
switch ( value )
|
||||
{
|
||||
case 866:
|
||||
encoding = wxFONTENCODING_CP866;
|
||||
break;
|
||||
|
||||
case 874:
|
||||
encoding = wxFONTENCODING_CP874;
|
||||
break;
|
||||
|
||||
case 932:
|
||||
encoding = wxFONTENCODING_CP932;
|
||||
break;
|
||||
|
||||
case 936:
|
||||
encoding = wxFONTENCODING_CP936;
|
||||
break;
|
||||
|
||||
case 949:
|
||||
encoding = wxFONTENCODING_CP949;
|
||||
break;
|
||||
|
||||
case 950:
|
||||
encoding = wxFONTENCODING_CP950;
|
||||
break;
|
||||
|
||||
case 1258:
|
||||
encoding = wxFONTENCODING_CP1258;
|
||||
break;
|
||||
|
||||
case 1361:
|
||||
encoding = wxFONTENCODING_CP1361;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//else: unknown
|
||||
}
|
||||
|
||||
return encoding;
|
||||
}
|
||||
|
||||
/* static */
|
||||
size_t wxFontMapperBase::GetSupportedEncodingsCount()
|
||||
{
|
||||
return WXSIZEOF(gs_encodings);
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxFontEncoding wxFontMapperBase::GetEncoding(size_t n)
|
||||
{
|
||||
wxCHECK_MSG( n < WXSIZEOF(gs_encodings), wxFONTENCODING_SYSTEM,
|
||||
wxT("wxFontMapper::GetEncoding(): invalid index") );
|
||||
|
||||
return gs_encodings[n];
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxString wxFontMapperBase::GetEncodingDescription(wxFontEncoding encoding)
|
||||
{
|
||||
if ( encoding == wxFONTENCODING_DEFAULT )
|
||||
{
|
||||
return _("Default encoding");
|
||||
}
|
||||
|
||||
const size_t count = WXSIZEOF(gs_encodingDescs);
|
||||
|
||||
for ( size_t i = 0; i < count; i++ )
|
||||
{
|
||||
if ( gs_encodings[i] == encoding )
|
||||
{
|
||||
return wxGetTranslation(gs_encodingDescs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
wxString str;
|
||||
str.Printf(_("Unknown encoding (%d)"), encoding);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxString wxFontMapperBase::GetEncodingName(wxFontEncoding encoding)
|
||||
{
|
||||
if ( encoding == wxFONTENCODING_DEFAULT )
|
||||
{
|
||||
return _("default");
|
||||
}
|
||||
|
||||
const size_t count = WXSIZEOF(gs_encodingNames);
|
||||
|
||||
for ( size_t i = 0; i < count; i++ )
|
||||
{
|
||||
if ( gs_encodings[i] == encoding )
|
||||
{
|
||||
return gs_encodingNames[i][0];
|
||||
}
|
||||
}
|
||||
|
||||
wxString str;
|
||||
str.Printf(_("unknown-%d"), encoding);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* static */
|
||||
const wxChar** wxFontMapperBase::GetAllEncodingNames(wxFontEncoding encoding)
|
||||
{
|
||||
static const wxChar* const dummy[] = { NULL };
|
||||
|
||||
for ( size_t i = 0; i < WXSIZEOF(gs_encodingNames); i++ )
|
||||
{
|
||||
if ( gs_encodings[i] == encoding )
|
||||
{
|
||||
return const_cast<const wxChar**>(gs_encodingNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return const_cast<const wxChar**>(dummy);
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxFontEncoding wxFontMapperBase::GetEncodingFromName(const wxString& name)
|
||||
{
|
||||
const size_t count = WXSIZEOF(gs_encodingNames);
|
||||
|
||||
for ( size_t i = 0; i < count; i++ )
|
||||
{
|
||||
for ( const wxChar* const* encName = gs_encodingNames[i]; *encName; ++encName )
|
||||
{
|
||||
if ( name.CmpNoCase(*encName) == 0 )
|
||||
return gs_encodings[i];
|
||||
}
|
||||
}
|
||||
|
||||
return wxFONTENCODING_MAX;
|
||||
}
|
||||
|
||||
#endif // wxUSE_FONTMAP
|
||||
@@ -0,0 +1,334 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/fontmgrcmn.cpp
|
||||
// Purpose: font management for ports that don't have their own
|
||||
// Author: Vaclav Slavik
|
||||
// Created: 2006-11-18
|
||||
// Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com)
|
||||
// (c) 2006 REA Elektronik GmbH
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/private/fontmgr.h"
|
||||
|
||||
#include "wx/listimpl.cpp"
|
||||
#include "wx/hashmap.h"
|
||||
|
||||
WX_DECLARE_LIST(wxFontInstance, wxFontInstanceList);
|
||||
WX_DEFINE_LIST(wxFontInstanceList)
|
||||
WX_DEFINE_LIST(wxFontBundleList)
|
||||
|
||||
WX_DECLARE_HASH_MAP(wxString, wxFontBundle*,
|
||||
wxStringHash, wxStringEqual,
|
||||
wxFontBundleHashBase);
|
||||
// in STL build, hash class is typedef to a template, so it can't be forward
|
||||
// declared, as we do; solve it by having a dummy class:
|
||||
class wxFontBundleHash : public wxFontBundleHashBase
|
||||
{
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFontFaceBase
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxFontFaceBase::wxFontFaceBase()
|
||||
: m_refCnt(0)
|
||||
{
|
||||
m_instances = new wxFontInstanceList;
|
||||
m_instances->DeleteContents(true);
|
||||
}
|
||||
|
||||
wxFontFaceBase::~wxFontFaceBase()
|
||||
{
|
||||
delete m_instances;
|
||||
}
|
||||
|
||||
void wxFontFaceBase::Acquire()
|
||||
{
|
||||
m_refCnt++;
|
||||
}
|
||||
|
||||
void wxFontFaceBase::Release()
|
||||
{
|
||||
if ( --m_refCnt == 0 )
|
||||
{
|
||||
m_instances->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
wxFontInstance *wxFontFaceBase::GetFontInstance(float ptSize, bool aa)
|
||||
{
|
||||
wxASSERT_MSG( m_refCnt > 0, wxT("font library not loaded!") );
|
||||
|
||||
for ( wxFontInstanceList::const_iterator i = m_instances->begin();
|
||||
i != m_instances->end(); ++i )
|
||||
{
|
||||
if ( (*i)->GetPointSize() == ptSize && (*i)->IsAntiAliased() == aa )
|
||||
return *i;
|
||||
}
|
||||
|
||||
wxFontInstance *i = CreateFontInstance(ptSize, aa);
|
||||
m_instances->Append(i);
|
||||
return i;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFontBundleBase
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxFontBundleBase::wxFontBundleBase()
|
||||
{
|
||||
for (int i = 0; i < FaceType_Max; i++)
|
||||
m_faces[i] = NULL;
|
||||
}
|
||||
|
||||
wxFontBundleBase::~wxFontBundleBase()
|
||||
{
|
||||
for (int i = 0; i < FaceType_Max; i++)
|
||||
delete m_faces[i];
|
||||
}
|
||||
|
||||
wxFontFace *wxFontBundleBase::GetFace(FaceType type) const
|
||||
{
|
||||
wxFontFace *f = m_faces[type];
|
||||
|
||||
wxCHECK_MSG( f, NULL, wxT("no such face in font bundle") );
|
||||
|
||||
f->Acquire();
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
wxFontFace *
|
||||
wxFontBundleBase::GetFaceForFont(const wxFontMgrFontRefData& font) const
|
||||
{
|
||||
wxASSERT_MSG( font.GetFaceName().empty() ||
|
||||
GetName().CmpNoCase(font.GetFaceName()) == 0,
|
||||
wxT("calling GetFaceForFont for incompatible font") );
|
||||
|
||||
int type = FaceType_Regular;
|
||||
|
||||
if ( font.GetNumericWeight() >= wxFONTWEIGHT_BOLD )
|
||||
type |= FaceType_Bold;
|
||||
|
||||
// FIXME -- this should read "if ( font->GetStyle() == wxFONTSTYLE_ITALIC )",
|
||||
// but since DFB doesn't support slant, we try to display it with italic
|
||||
// face (better than nothing...)
|
||||
if ( font.GetStyle() == wxFONTSTYLE_ITALIC
|
||||
|| font.GetStyle() == wxFONTSTYLE_SLANT )
|
||||
{
|
||||
if ( HasFace((FaceType)(type | FaceType_Italic)) )
|
||||
type |= FaceType_Italic;
|
||||
}
|
||||
|
||||
if ( !HasFace((FaceType)type) )
|
||||
{
|
||||
// if we can't get the exact font requested, substitute it with
|
||||
// some other variant:
|
||||
for (int i = 0; i < FaceType_Max; i++)
|
||||
{
|
||||
if ( HasFace((FaceType)i) )
|
||||
return GetFace((FaceType)i);
|
||||
}
|
||||
|
||||
wxFAIL_MSG( wxT("no face") );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return GetFace((FaceType)type);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFontsManagerBase
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxFontsManager *wxFontsManagerBase::ms_instance = NULL;
|
||||
|
||||
wxFontsManagerBase::wxFontsManagerBase()
|
||||
{
|
||||
m_hash = new wxFontBundleHash();
|
||||
m_list = new wxFontBundleList;
|
||||
m_list->DeleteContents(true);
|
||||
}
|
||||
|
||||
wxFontsManagerBase::~wxFontsManagerBase()
|
||||
{
|
||||
delete m_hash;
|
||||
delete m_list;
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxFontsManager *wxFontsManagerBase::Get()
|
||||
{
|
||||
if ( !ms_instance )
|
||||
ms_instance = new wxFontsManager();
|
||||
return ms_instance;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void wxFontsManagerBase::CleanUp()
|
||||
{
|
||||
wxDELETE(ms_instance);
|
||||
}
|
||||
|
||||
wxFontBundle *wxFontsManagerBase::GetBundle(const wxString& name) const
|
||||
{
|
||||
return (*m_hash)[name.Lower()];
|
||||
}
|
||||
|
||||
wxFontBundle *
|
||||
wxFontsManagerBase::GetBundleForFont(const wxFontMgrFontRefData& font) const
|
||||
{
|
||||
wxFontBundle *bundle = NULL;
|
||||
|
||||
wxString facename = font.GetFaceName();
|
||||
if ( !facename.empty() )
|
||||
bundle = GetBundle(facename);
|
||||
|
||||
if ( !bundle )
|
||||
{
|
||||
facename = GetDefaultFacename((wxFontFamily)font.GetFamily());
|
||||
if ( !facename.empty() )
|
||||
bundle = GetBundle(facename);
|
||||
}
|
||||
|
||||
if ( !bundle )
|
||||
{
|
||||
if ( m_list->GetFirst() )
|
||||
bundle = m_list->GetFirst()->GetData();
|
||||
else
|
||||
wxFAIL_MSG(wxT("Fatal error, no fonts available!"));
|
||||
}
|
||||
|
||||
return bundle;
|
||||
}
|
||||
|
||||
void wxFontsManagerBase::AddBundle(wxFontBundle *bundle)
|
||||
{
|
||||
(*m_hash)[bundle->GetName().Lower()] = bundle;
|
||||
m_list->Append(bundle);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFontMgrFontRefData
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxFontMgrFontRefData::wxFontMgrFontRefData(int size,
|
||||
wxFontFamily family,
|
||||
wxFontStyle style,
|
||||
int weight,
|
||||
bool underlined,
|
||||
const wxString& faceName,
|
||||
wxFontEncoding encoding)
|
||||
{
|
||||
if ( family == wxFONTFAMILY_DEFAULT )
|
||||
family = wxFONTFAMILY_SWISS;
|
||||
if ( size == wxDEFAULT )
|
||||
size = 12;
|
||||
|
||||
m_info.family = (wxFontFamily)family;
|
||||
m_info.faceName = faceName;
|
||||
m_info.style = (wxFontStyle)style;
|
||||
m_info.weight = weight;
|
||||
m_info.pointSize = size;
|
||||
m_info.underlined = underlined;
|
||||
m_info.encoding = encoding;
|
||||
|
||||
m_fontFace = NULL;
|
||||
m_fontBundle = NULL;
|
||||
m_fontValid = false;
|
||||
}
|
||||
|
||||
wxFontMgrFontRefData::wxFontMgrFontRefData(const wxFontMgrFontRefData& data)
|
||||
: m_info(data.m_info)
|
||||
{
|
||||
m_fontFace = data.m_fontFace;
|
||||
m_fontBundle = data.m_fontBundle;
|
||||
m_fontValid = data.m_fontValid;
|
||||
if ( m_fontFace )
|
||||
m_fontFace->Acquire();
|
||||
}
|
||||
|
||||
wxFontMgrFontRefData::~wxFontMgrFontRefData()
|
||||
{
|
||||
if ( m_fontFace )
|
||||
m_fontFace->Release();
|
||||
}
|
||||
|
||||
wxFontBundle *wxFontMgrFontRefData::GetFontBundle() const
|
||||
{
|
||||
wxConstCast(this, wxFontMgrFontRefData)->EnsureValidFont();
|
||||
return m_fontBundle;
|
||||
}
|
||||
|
||||
wxFontInstance *
|
||||
wxFontMgrFontRefData::GetFontInstance(float scale, bool antialiased) const
|
||||
{
|
||||
wxConstCast(this, wxFontMgrFontRefData)->EnsureValidFont();
|
||||
return m_fontFace->GetFontInstance(m_info.pointSize * scale,
|
||||
antialiased);
|
||||
}
|
||||
|
||||
void wxFontMgrFontRefData::SetFractionalPointSize(double pointSize)
|
||||
{
|
||||
m_info.pointSize = pointSize;
|
||||
m_fontValid = false;
|
||||
}
|
||||
|
||||
void wxFontMgrFontRefData::SetFamily(wxFontFamily family)
|
||||
{
|
||||
m_info.family = family;
|
||||
m_fontValid = false;
|
||||
}
|
||||
|
||||
void wxFontMgrFontRefData::SetStyle(wxFontStyle style)
|
||||
{
|
||||
m_info.style = style;
|
||||
m_fontValid = false;
|
||||
}
|
||||
|
||||
void wxFontMgrFontRefData::SetNumericWeight(int weight)
|
||||
{
|
||||
m_info.weight = weight;
|
||||
m_fontValid = false;
|
||||
}
|
||||
|
||||
void wxFontMgrFontRefData::SetFaceName(const wxString& faceName)
|
||||
{
|
||||
m_info.faceName = faceName;
|
||||
m_fontValid = false;
|
||||
}
|
||||
|
||||
void wxFontMgrFontRefData::SetUnderlined(bool underlined)
|
||||
{
|
||||
m_info.underlined = underlined;
|
||||
m_fontValid = false;
|
||||
}
|
||||
|
||||
void wxFontMgrFontRefData::SetEncoding(wxFontEncoding encoding)
|
||||
{
|
||||
m_info.encoding = encoding;
|
||||
m_fontValid = false;
|
||||
}
|
||||
|
||||
void wxFontMgrFontRefData::EnsureValidFont()
|
||||
{
|
||||
if ( !m_fontValid )
|
||||
{
|
||||
wxFontFace *old = m_fontFace;
|
||||
|
||||
m_fontBundle = wxFontsManager::Get()->GetBundleForFont(*this);
|
||||
m_fontFace = m_fontBundle->GetFaceForFont(*this);
|
||||
|
||||
if ( old )
|
||||
old->Release();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,518 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/fs_arc.cpp
|
||||
// Purpose: wxArchive file system
|
||||
// Author: Vaclav Slavik, Mike Wetherell
|
||||
// Copyright: (c) 1999 Vaclav Slavik, (c) 2006 Mike Wetherell
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
#if wxUSE_FS_ARCHIVE
|
||||
|
||||
#include "wx/fs_arc.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/intl.h"
|
||||
#include "wx/log.h"
|
||||
#endif
|
||||
|
||||
#include "wx/archive.h"
|
||||
#include "wx/private/fileback.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// wxArchiveFSCacheDataImpl
|
||||
//
|
||||
// Holds the catalog of an archive file, and if it is being read from a
|
||||
// non-seekable stream, a copy of its backing file.
|
||||
//
|
||||
// This class is actually the reference counted implementation for the
|
||||
// wxArchiveFSCacheData class below. It was done that way to allow sharing
|
||||
// between instances of wxFileSystem, though that's a feature not used in this
|
||||
// version.
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
WX_DECLARE_STRING_HASH_MAP(wxArchiveEntry*, wxArchiveFSEntryHash);
|
||||
|
||||
struct wxArchiveFSEntry
|
||||
{
|
||||
wxArchiveEntry *entry;
|
||||
wxArchiveFSEntry *next;
|
||||
};
|
||||
|
||||
class wxArchiveFSCacheDataImpl
|
||||
{
|
||||
public:
|
||||
wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory,
|
||||
const wxBackingFile& backer);
|
||||
wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory,
|
||||
wxInputStream *stream);
|
||||
|
||||
~wxArchiveFSCacheDataImpl();
|
||||
|
||||
void Release() { if (--m_refcount == 0) delete this; }
|
||||
wxArchiveFSCacheDataImpl *AddRef() { m_refcount++; return this; }
|
||||
|
||||
wxArchiveEntry *Get(const wxString& name);
|
||||
wxInputStream *NewStream() const;
|
||||
|
||||
wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse);
|
||||
|
||||
private:
|
||||
wxArchiveFSEntry *AddToCache(wxArchiveEntry *entry);
|
||||
void CloseStreams();
|
||||
|
||||
int m_refcount;
|
||||
|
||||
wxArchiveFSEntryHash m_hash;
|
||||
wxArchiveFSEntry *m_begin;
|
||||
wxArchiveFSEntry **m_endptr;
|
||||
|
||||
wxBackingFile m_backer;
|
||||
wxInputStream *m_stream;
|
||||
wxArchiveInputStream *m_archive;
|
||||
};
|
||||
|
||||
wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl(
|
||||
const wxArchiveClassFactory& factory,
|
||||
const wxBackingFile& backer)
|
||||
: m_refcount(1),
|
||||
m_begin(NULL),
|
||||
m_endptr(&m_begin),
|
||||
m_backer(backer),
|
||||
m_stream(new wxBackedInputStream(backer)),
|
||||
m_archive(factory.NewStream(*m_stream))
|
||||
{
|
||||
}
|
||||
|
||||
wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl(
|
||||
const wxArchiveClassFactory& factory,
|
||||
wxInputStream *stream)
|
||||
: m_refcount(1),
|
||||
m_begin(NULL),
|
||||
m_endptr(&m_begin),
|
||||
m_stream(stream),
|
||||
m_archive(factory.NewStream(*m_stream))
|
||||
{
|
||||
}
|
||||
|
||||
wxArchiveFSCacheDataImpl::~wxArchiveFSCacheDataImpl()
|
||||
{
|
||||
WX_CLEAR_HASH_MAP(wxArchiveFSEntryHash, m_hash);
|
||||
|
||||
wxArchiveFSEntry *entry = m_begin;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
wxArchiveFSEntry *next = entry->next;
|
||||
delete entry;
|
||||
entry = next;
|
||||
}
|
||||
|
||||
CloseStreams();
|
||||
}
|
||||
|
||||
wxArchiveFSEntry *wxArchiveFSCacheDataImpl::AddToCache(wxArchiveEntry *entry)
|
||||
{
|
||||
m_hash[entry->GetName(wxPATH_UNIX)] = entry;
|
||||
wxArchiveFSEntry *fse = new wxArchiveFSEntry;
|
||||
*m_endptr = fse;
|
||||
(*m_endptr)->entry = entry;
|
||||
(*m_endptr)->next = NULL;
|
||||
m_endptr = &(*m_endptr)->next;
|
||||
return fse;
|
||||
}
|
||||
|
||||
void wxArchiveFSCacheDataImpl::CloseStreams()
|
||||
{
|
||||
wxDELETE(m_archive);
|
||||
wxDELETE(m_stream);
|
||||
}
|
||||
|
||||
wxArchiveEntry *wxArchiveFSCacheDataImpl::Get(const wxString& name)
|
||||
{
|
||||
wxArchiveFSEntryHash::iterator it = m_hash.find(name);
|
||||
|
||||
if (it != m_hash.end())
|
||||
return it->second;
|
||||
|
||||
if (!m_archive)
|
||||
return NULL;
|
||||
|
||||
wxArchiveEntry *entry;
|
||||
|
||||
while ((entry = m_archive->GetNextEntry()) != NULL)
|
||||
{
|
||||
AddToCache(entry);
|
||||
|
||||
if (entry->GetName(wxPATH_UNIX) == name)
|
||||
return entry;
|
||||
}
|
||||
|
||||
CloseStreams();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wxInputStream* wxArchiveFSCacheDataImpl::NewStream() const
|
||||
{
|
||||
if (m_backer)
|
||||
return new wxBackedInputStream(m_backer);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wxArchiveFSEntry *wxArchiveFSCacheDataImpl::GetNext(wxArchiveFSEntry *fse)
|
||||
{
|
||||
wxArchiveFSEntry *next = fse ? fse->next : m_begin;
|
||||
|
||||
if (!next && m_archive)
|
||||
{
|
||||
wxArchiveEntry *entry = m_archive->GetNextEntry();
|
||||
|
||||
if (entry)
|
||||
next = AddToCache(entry);
|
||||
else
|
||||
CloseStreams();
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// wxArchiveFSCacheData
|
||||
//
|
||||
// This is the inteface for wxArchiveFSCacheDataImpl above. Holds the catalog
|
||||
// of an archive file, and if it is being read from a non-seekable stream, a
|
||||
// copy of its backing file.
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class wxArchiveFSCacheData
|
||||
{
|
||||
public:
|
||||
wxArchiveFSCacheData() : m_impl(NULL) { }
|
||||
wxArchiveFSCacheData(const wxArchiveClassFactory& factory,
|
||||
const wxBackingFile& backer);
|
||||
wxArchiveFSCacheData(const wxArchiveClassFactory& factory,
|
||||
wxInputStream *stream);
|
||||
|
||||
wxArchiveFSCacheData(const wxArchiveFSCacheData& data);
|
||||
wxArchiveFSCacheData& operator=(const wxArchiveFSCacheData& data);
|
||||
|
||||
~wxArchiveFSCacheData() { if (m_impl) m_impl->Release(); }
|
||||
|
||||
wxArchiveEntry *Get(const wxString& name) { return m_impl->Get(name); }
|
||||
wxInputStream *NewStream() const { return m_impl->NewStream(); }
|
||||
wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse)
|
||||
{ return m_impl->GetNext(fse); }
|
||||
|
||||
private:
|
||||
wxArchiveFSCacheDataImpl *m_impl;
|
||||
};
|
||||
|
||||
wxArchiveFSCacheData::wxArchiveFSCacheData(
|
||||
const wxArchiveClassFactory& factory,
|
||||
const wxBackingFile& backer)
|
||||
: m_impl(new wxArchiveFSCacheDataImpl(factory, backer))
|
||||
{
|
||||
}
|
||||
|
||||
wxArchiveFSCacheData::wxArchiveFSCacheData(
|
||||
const wxArchiveClassFactory& factory,
|
||||
wxInputStream *stream)
|
||||
: m_impl(new wxArchiveFSCacheDataImpl(factory, stream))
|
||||
{
|
||||
}
|
||||
|
||||
wxArchiveFSCacheData::wxArchiveFSCacheData(const wxArchiveFSCacheData& data)
|
||||
: m_impl(data.m_impl ? data.m_impl->AddRef() : NULL)
|
||||
{
|
||||
}
|
||||
|
||||
wxArchiveFSCacheData& wxArchiveFSCacheData::operator=(
|
||||
const wxArchiveFSCacheData& data)
|
||||
{
|
||||
if (data.m_impl != m_impl)
|
||||
{
|
||||
if (m_impl)
|
||||
m_impl->Release();
|
||||
|
||||
m_impl = data.m_impl;
|
||||
|
||||
if (m_impl)
|
||||
m_impl->AddRef();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// wxArchiveFSCache
|
||||
//
|
||||
// wxArchiveFSCacheData caches a single archive, and this class holds a
|
||||
// collection of them to cache all the archives accessed by this instance
|
||||
// of wxFileSystem.
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
WX_DECLARE_STRING_HASH_MAP(wxArchiveFSCacheData, wxArchiveFSCacheDataHash);
|
||||
|
||||
class wxArchiveFSCache
|
||||
{
|
||||
public:
|
||||
wxArchiveFSCache() { }
|
||||
~wxArchiveFSCache() { }
|
||||
|
||||
wxArchiveFSCacheData* Add(const wxString& name,
|
||||
const wxArchiveClassFactory& factory,
|
||||
wxInputStream *stream);
|
||||
|
||||
wxArchiveFSCacheData *Get(const wxString& name);
|
||||
|
||||
private:
|
||||
wxArchiveFSCacheDataHash m_hash;
|
||||
};
|
||||
|
||||
wxArchiveFSCacheData* wxArchiveFSCache::Add(
|
||||
const wxString& name,
|
||||
const wxArchiveClassFactory& factory,
|
||||
wxInputStream *stream)
|
||||
{
|
||||
wxArchiveFSCacheData& data = m_hash[name];
|
||||
|
||||
if (stream->IsSeekable())
|
||||
data = wxArchiveFSCacheData(factory, stream);
|
||||
else
|
||||
data = wxArchiveFSCacheData(factory, wxBackingFile(stream));
|
||||
|
||||
return &data;
|
||||
}
|
||||
|
||||
wxArchiveFSCacheData *wxArchiveFSCache::Get(const wxString& name)
|
||||
{
|
||||
wxArchiveFSCacheDataHash::iterator it;
|
||||
|
||||
if ((it = m_hash.find(name)) != m_hash.end())
|
||||
return &it->second;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// wxArchiveFSHandler
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxArchiveFSHandler, wxFileSystemHandler);
|
||||
|
||||
wxArchiveFSHandler::wxArchiveFSHandler()
|
||||
: wxFileSystemHandler()
|
||||
{
|
||||
m_Archive = NULL;
|
||||
m_FindEntry = NULL;
|
||||
m_AllowDirs = m_AllowFiles = true;
|
||||
m_DirsFound = NULL;
|
||||
m_cache = NULL;
|
||||
}
|
||||
|
||||
wxArchiveFSHandler::~wxArchiveFSHandler()
|
||||
{
|
||||
Cleanup();
|
||||
delete m_cache;
|
||||
}
|
||||
|
||||
void wxArchiveFSHandler::Cleanup()
|
||||
{
|
||||
wxDELETE(m_DirsFound);
|
||||
}
|
||||
|
||||
bool wxArchiveFSHandler::CanOpen(const wxString& location)
|
||||
{
|
||||
wxString p = GetProtocol(location);
|
||||
return wxArchiveClassFactory::Find(p) != NULL;
|
||||
}
|
||||
|
||||
wxFSFile* wxArchiveFSHandler::OpenFile(
|
||||
wxFileSystem& WXUNUSED(fs),
|
||||
const wxString& location)
|
||||
{
|
||||
wxString right = GetRightLocation(location);
|
||||
wxString left = GetLeftLocation(location);
|
||||
wxString protocol = GetProtocol(location);
|
||||
wxString key = left + wxT("#") + protocol + wxT(":");
|
||||
|
||||
if (right.Contains(wxT("./")))
|
||||
{
|
||||
if (right.GetChar(0) != wxT('/')) right = wxT('/') + right;
|
||||
wxFileName rightPart(right, wxPATH_UNIX);
|
||||
rightPart.Normalize(wxPATH_NORM_DOTS, wxT("/"), wxPATH_UNIX);
|
||||
right = rightPart.GetFullPath(wxPATH_UNIX);
|
||||
}
|
||||
|
||||
if (!right.empty() && right.GetChar(0) == wxT('/')) right = right.Mid(1);
|
||||
|
||||
if (!m_cache)
|
||||
m_cache = new wxArchiveFSCache;
|
||||
|
||||
const wxArchiveClassFactory *factory;
|
||||
factory = wxArchiveClassFactory::Find(protocol);
|
||||
if (!factory)
|
||||
return NULL;
|
||||
|
||||
wxArchiveFSCacheData *cached = m_cache->Get(key);
|
||||
if (!cached)
|
||||
{
|
||||
wxFSFile *leftFile = m_fs.OpenFile(left);
|
||||
if (!leftFile)
|
||||
return NULL;
|
||||
cached = m_cache->Add(key, *factory, leftFile->DetachStream());
|
||||
delete leftFile;
|
||||
}
|
||||
|
||||
wxArchiveEntry *entry = cached->Get(right);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
wxInputStream *leftStream = cached->NewStream();
|
||||
if (!leftStream)
|
||||
{
|
||||
wxFSFile *leftFile = m_fs.OpenFile(left);
|
||||
if (!leftFile)
|
||||
return NULL;
|
||||
leftStream = leftFile->DetachStream();
|
||||
delete leftFile;
|
||||
}
|
||||
|
||||
wxArchiveInputStream *s = factory->NewStream(leftStream);
|
||||
if ( !s )
|
||||
return NULL;
|
||||
|
||||
s->OpenEntry(*entry);
|
||||
|
||||
if (!s->IsOk())
|
||||
{
|
||||
delete s;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new wxFSFile(s,
|
||||
key + right,
|
||||
wxEmptyString,
|
||||
GetAnchor(location)
|
||||
#if wxUSE_DATETIME
|
||||
, entry->GetDateTime()
|
||||
#endif // wxUSE_DATETIME
|
||||
);
|
||||
}
|
||||
|
||||
wxString wxArchiveFSHandler::FindFirst(const wxString& spec, int flags)
|
||||
{
|
||||
wxString right = GetRightLocation(spec);
|
||||
wxString left = GetLeftLocation(spec);
|
||||
wxString protocol = GetProtocol(spec);
|
||||
wxString key = left + wxT("#") + protocol + wxT(":");
|
||||
|
||||
if (!right.empty() && right.Last() == wxT('/')) right.RemoveLast();
|
||||
|
||||
if (!m_cache)
|
||||
m_cache = new wxArchiveFSCache;
|
||||
|
||||
const wxArchiveClassFactory *factory;
|
||||
factory = wxArchiveClassFactory::Find(protocol);
|
||||
if (!factory)
|
||||
return wxEmptyString;
|
||||
|
||||
m_Archive = m_cache->Get(key);
|
||||
if (!m_Archive)
|
||||
{
|
||||
wxFSFile *leftFile = m_fs.OpenFile(left);
|
||||
if (!leftFile)
|
||||
return wxEmptyString;
|
||||
m_Archive = m_cache->Add(key, *factory, leftFile->DetachStream());
|
||||
delete leftFile;
|
||||
}
|
||||
|
||||
m_FindEntry = NULL;
|
||||
|
||||
switch (flags)
|
||||
{
|
||||
case wxFILE:
|
||||
m_AllowDirs = false, m_AllowFiles = true; break;
|
||||
case wxDIR:
|
||||
m_AllowDirs = true, m_AllowFiles = false; break;
|
||||
default:
|
||||
m_AllowDirs = m_AllowFiles = true; break;
|
||||
}
|
||||
|
||||
m_ZipFile = key;
|
||||
|
||||
m_Pattern = right.AfterLast(wxT('/'));
|
||||
m_BaseDir = right.BeforeLast(wxT('/'));
|
||||
if (m_BaseDir.StartsWith(wxT("/")))
|
||||
m_BaseDir = m_BaseDir.Mid(1);
|
||||
|
||||
if (m_Archive)
|
||||
{
|
||||
if (m_AllowDirs)
|
||||
{
|
||||
delete m_DirsFound;
|
||||
m_DirsFound = new wxArchiveFilenameHashMap();
|
||||
if (right.empty()) // allow "/" to match the archive root
|
||||
return spec;
|
||||
}
|
||||
return DoFind();
|
||||
}
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
wxString wxArchiveFSHandler::FindNext()
|
||||
{
|
||||
if (!m_Archive) return wxEmptyString;
|
||||
return DoFind();
|
||||
}
|
||||
|
||||
wxString wxArchiveFSHandler::DoFind()
|
||||
{
|
||||
wxString namestr, dir, filename;
|
||||
wxString match;
|
||||
|
||||
while (match.empty())
|
||||
{
|
||||
m_FindEntry = m_Archive->GetNext(m_FindEntry);
|
||||
|
||||
if (!m_FindEntry)
|
||||
{
|
||||
m_Archive = NULL;
|
||||
m_FindEntry = NULL;
|
||||
break;
|
||||
}
|
||||
namestr = m_FindEntry->entry->GetName(wxPATH_UNIX);
|
||||
|
||||
if (m_AllowDirs)
|
||||
{
|
||||
dir = namestr.BeforeLast(wxT('/'));
|
||||
while (!dir.empty())
|
||||
{
|
||||
if( m_DirsFound->find(dir) == m_DirsFound->end() )
|
||||
{
|
||||
(*m_DirsFound)[dir] = 1;
|
||||
filename = dir.AfterLast(wxT('/'));
|
||||
dir = dir.BeforeLast(wxT('/'));
|
||||
if (!filename.empty() && m_BaseDir == dir &&
|
||||
wxMatchWild(m_Pattern, filename, false))
|
||||
match = m_ZipFile + dir + wxT("/") + filename;
|
||||
}
|
||||
else
|
||||
break; // already tranversed
|
||||
}
|
||||
}
|
||||
|
||||
filename = namestr.AfterLast(wxT('/'));
|
||||
dir = namestr.BeforeLast(wxT('/'));
|
||||
if (m_AllowFiles && !filename.empty() && m_BaseDir == dir &&
|
||||
wxMatchWild(m_Pattern, filename, false))
|
||||
match = m_ZipFile + namestr;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
#endif // wxUSE_FS_ARCHIVE
|
||||
@@ -0,0 +1,88 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/fs_filter.cpp
|
||||
// Purpose: wxFilter file system handler
|
||||
// Author: Mike Wetherell
|
||||
// Copyright: (c) 2006 Mike Wetherell
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_FILESYSTEM
|
||||
|
||||
#include "wx/fs_filter.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#endif
|
||||
|
||||
#include "wx/scopedptr.h"
|
||||
|
||||
wxDEFINE_SCOPED_PTR_TYPE(wxFSFile)
|
||||
wxDEFINE_SCOPED_PTR_TYPE(wxInputStream)
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// wxFilterFSHandler
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool wxFilterFSHandler::CanOpen(const wxString& location)
|
||||
{
|
||||
return wxFilterClassFactory::Find(GetProtocol(location)) != NULL;
|
||||
}
|
||||
|
||||
wxFSFile* wxFilterFSHandler::OpenFile(
|
||||
wxFileSystem& fs,
|
||||
const wxString& location)
|
||||
{
|
||||
wxString right = GetRightLocation(location);
|
||||
if (!right.empty())
|
||||
return NULL;
|
||||
|
||||
wxString protocol = GetProtocol(location);
|
||||
const wxFilterClassFactory *factory = wxFilterClassFactory::Find(protocol);
|
||||
if (!factory)
|
||||
return NULL;
|
||||
|
||||
wxString left = GetLeftLocation(location);
|
||||
wxFSFilePtr leftFile(fs.OpenFile(left));
|
||||
if (!leftFile.get())
|
||||
return NULL;
|
||||
|
||||
wxInputStreamPtr leftStream(leftFile->DetachStream());
|
||||
if (!leftStream.get() || !leftStream->IsOk())
|
||||
return NULL;
|
||||
|
||||
wxInputStreamPtr stream(factory->NewStream(leftStream.release()));
|
||||
|
||||
// The way compressed streams are supposed to be served is e.g.:
|
||||
// Content-type: application/postscript
|
||||
// Content-encoding: gzip
|
||||
// So the mime type should be just the mime type of the lhs. However check
|
||||
// whether the mime type is that of this compression format (e.g.
|
||||
// application/gzip). If so pop any extension and try GetMimeTypeFromExt,
|
||||
// e.g. if it were '.ps.gz' pop the '.gz' and try looking up '.ps'
|
||||
wxString mime = leftFile->GetMimeType();
|
||||
if (factory->CanHandle(mime, wxSTREAM_MIMETYPE))
|
||||
mime = GetMimeTypeFromExt(factory->PopExtension(left));
|
||||
|
||||
return new wxFSFile(stream.release(),
|
||||
left + wxT("#") + protocol + wxT(":") + right,
|
||||
mime,
|
||||
GetAnchor(location)
|
||||
#if wxUSE_DATETIME
|
||||
, leftFile->GetModificationTime()
|
||||
#endif // wxUSE_DATETIME
|
||||
);
|
||||
}
|
||||
|
||||
wxString wxFilterFSHandler::FindFirst(const wxString& WXUNUSED(spec), int WXUNUSED(flags))
|
||||
{
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
wxString wxFilterFSHandler::FindNext()
|
||||
{
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
#endif //wxUSE_FILESYSTEM
|
||||
@@ -0,0 +1,168 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/fs_inet.cpp
|
||||
// Purpose: HTTP and FTP file system
|
||||
// Author: Vaclav Slavik
|
||||
// Copyright: (c) 1999 Vaclav Slavik
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if !wxUSE_SOCKETS
|
||||
#undef wxUSE_FS_INET
|
||||
#define wxUSE_FS_INET 0
|
||||
#endif
|
||||
|
||||
#if wxUSE_FILESYSTEM && wxUSE_FS_INET
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/module.h"
|
||||
#endif
|
||||
|
||||
#include "wx/wfstream.h"
|
||||
#include "wx/url.h"
|
||||
#include "wx/filesys.h"
|
||||
#include "wx/fs_inet.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helper classes
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// This stream deletes the file when destroyed
|
||||
class wxTemporaryFileInputStream : public wxFileInputStream
|
||||
{
|
||||
public:
|
||||
wxTemporaryFileInputStream(const wxString& filename) :
|
||||
wxFileInputStream(filename), m_filename(filename) {}
|
||||
|
||||
virtual ~wxTemporaryFileInputStream()
|
||||
{
|
||||
// NB: copied from wxFileInputStream dtor, we need to do it before
|
||||
// wxRemoveFile
|
||||
if (m_file_destroy)
|
||||
{
|
||||
delete m_file;
|
||||
m_file_destroy = false;
|
||||
}
|
||||
wxRemoveFile(m_filename);
|
||||
}
|
||||
|
||||
protected:
|
||||
wxString m_filename;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxInternetFSHandler
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static wxString StripProtocolAnchor(const wxString& location)
|
||||
{
|
||||
wxString myloc(location.BeforeLast(wxT('#')));
|
||||
if (myloc.empty()) myloc = location.AfterFirst(wxT(':'));
|
||||
else myloc = myloc.AfterFirst(wxT(':'));
|
||||
|
||||
// fix malformed url:
|
||||
if (!myloc.Left(2).IsSameAs(wxT("//")))
|
||||
{
|
||||
if (myloc.GetChar(0) != wxT('/')) myloc = wxT("//") + myloc;
|
||||
else myloc = wxT("/") + myloc;
|
||||
}
|
||||
if (myloc.Mid(2).Find(wxT('/')) == wxNOT_FOUND) myloc << wxT('/');
|
||||
|
||||
return myloc;
|
||||
}
|
||||
|
||||
|
||||
bool wxInternetFSHandler::CanOpen(const wxString& location)
|
||||
{
|
||||
#if wxUSE_URL
|
||||
wxString p = GetProtocol(location);
|
||||
if ((p == wxT("http")) || (p == wxT("ftp")))
|
||||
{
|
||||
wxURL url(p + wxT(":") + StripProtocolAnchor(location));
|
||||
return (url.GetError() == wxURL_NOERR);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
wxFSFile* wxInternetFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs),
|
||||
const wxString& location)
|
||||
{
|
||||
#if !wxUSE_URL
|
||||
return NULL;
|
||||
#else
|
||||
wxString right =
|
||||
GetProtocol(location) + wxT(":") + StripProtocolAnchor(location);
|
||||
|
||||
wxURL url(right);
|
||||
if (url.GetError() == wxURL_NOERR)
|
||||
{
|
||||
wxInputStream *s = url.GetInputStream();
|
||||
if (s)
|
||||
{
|
||||
wxString tmpfile =
|
||||
wxFileName::CreateTempFileName(wxT("wxhtml"));
|
||||
|
||||
{ // now copy streams content to temporary file:
|
||||
wxFileOutputStream sout(tmpfile);
|
||||
s->Read(sout);
|
||||
}
|
||||
delete s;
|
||||
|
||||
// Content-Type header, as defined by the RFC 2045, has the form of
|
||||
// "type/subtype" optionally followed by (multiple) "; parameter"
|
||||
// and we need just the MIME type here.
|
||||
const wxString& content = url.GetProtocol().GetContentType();
|
||||
wxString mimetype = content.BeforeFirst(';');
|
||||
mimetype.Trim();
|
||||
|
||||
return new wxFSFile(new wxTemporaryFileInputStream(tmpfile),
|
||||
right,
|
||||
mimetype,
|
||||
GetAnchor(location)
|
||||
#if wxUSE_DATETIME
|
||||
, wxDateTime::Now()
|
||||
#endif // wxUSE_DATETIME
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; // incorrect URL
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
class wxFileSystemInternetModule : public wxModule
|
||||
{
|
||||
wxDECLARE_DYNAMIC_CLASS(wxFileSystemInternetModule);
|
||||
|
||||
public:
|
||||
wxFileSystemInternetModule() :
|
||||
wxModule(),
|
||||
m_handler(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool OnInit() wxOVERRIDE
|
||||
{
|
||||
m_handler = new wxInternetFSHandler;
|
||||
wxFileSystem::AddHandler(m_handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void OnExit() wxOVERRIDE
|
||||
{
|
||||
delete wxFileSystem::RemoveHandler(m_handler);
|
||||
}
|
||||
|
||||
private:
|
||||
wxFileSystemHandler* m_handler;
|
||||
};
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxFileSystemInternetModule, wxModule);
|
||||
|
||||
#endif // wxUSE_FILESYSTEM && wxUSE_FS_INET
|
||||
@@ -0,0 +1,274 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/fs_mem.cpp
|
||||
// Purpose: in-memory file system
|
||||
// Author: Vaclav Slavik
|
||||
// Copyright: (c) 2000 Vaclav Slavik
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_FILESYSTEM && wxUSE_STREAMS
|
||||
|
||||
#include "wx/fs_mem.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/intl.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/wxcrtvararg.h"
|
||||
#if wxUSE_GUI
|
||||
#include "wx/image.h"
|
||||
#endif // wxUSE_GUI
|
||||
#endif
|
||||
|
||||
#include "wx/mstream.h"
|
||||
|
||||
// represents a file entry in wxMemoryFS
|
||||
class wxMemoryFSFile
|
||||
{
|
||||
public:
|
||||
wxMemoryFSFile(const void *data, size_t len, const wxString& mime)
|
||||
{
|
||||
m_Data = new char[len];
|
||||
memcpy(m_Data, data, len);
|
||||
m_Len = len;
|
||||
m_MimeType = mime;
|
||||
InitTime();
|
||||
}
|
||||
|
||||
wxMemoryFSFile(const wxMemoryOutputStream& stream, const wxString& mime)
|
||||
{
|
||||
m_Len = stream.GetSize();
|
||||
m_Data = new char[m_Len];
|
||||
stream.CopyTo(m_Data, m_Len);
|
||||
m_MimeType = mime;
|
||||
InitTime();
|
||||
}
|
||||
|
||||
virtual ~wxMemoryFSFile()
|
||||
{
|
||||
delete[] m_Data;
|
||||
}
|
||||
|
||||
char *m_Data;
|
||||
size_t m_Len;
|
||||
wxString m_MimeType;
|
||||
#if wxUSE_DATETIME
|
||||
wxDateTime m_Time;
|
||||
#endif // wxUSE_DATETIME
|
||||
|
||||
private:
|
||||
void InitTime()
|
||||
{
|
||||
#if wxUSE_DATETIME
|
||||
m_Time = wxDateTime::Now();
|
||||
#endif // wxUSE_DATETIME
|
||||
}
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxMemoryFSFile);
|
||||
};
|
||||
|
||||
#if wxUSE_BASE
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// wxMemoryFSHandler
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
wxMemoryFSHash wxMemoryFSHandlerBase::m_Hash;
|
||||
|
||||
|
||||
wxMemoryFSHandlerBase::wxMemoryFSHandlerBase() : wxFileSystemHandler()
|
||||
{
|
||||
}
|
||||
|
||||
wxMemoryFSHandlerBase::~wxMemoryFSHandlerBase()
|
||||
{
|
||||
// as only one copy of FS handler is supposed to exist, we may silently
|
||||
// delete static data here. (There is no way how to remove FS handler from
|
||||
// wxFileSystem other than releasing _all_ handlers.)
|
||||
WX_CLEAR_HASH_MAP(wxMemoryFSHash, m_Hash);
|
||||
}
|
||||
|
||||
bool wxMemoryFSHandlerBase::CanOpen(const wxString& location)
|
||||
{
|
||||
return GetProtocol(location) == "memory";
|
||||
}
|
||||
|
||||
wxFSFile * wxMemoryFSHandlerBase::OpenFile(wxFileSystem& WXUNUSED(fs),
|
||||
const wxString& location)
|
||||
{
|
||||
wxMemoryFSHash::const_iterator i = m_Hash.find(GetRightLocation(location));
|
||||
if ( i == m_Hash.end() )
|
||||
return NULL;
|
||||
|
||||
const wxMemoryFSFile * const obj = i->second;
|
||||
|
||||
return new wxFSFile
|
||||
(
|
||||
new wxMemoryInputStream(obj->m_Data, obj->m_Len),
|
||||
location,
|
||||
obj->m_MimeType,
|
||||
GetAnchor(location)
|
||||
#if wxUSE_DATETIME
|
||||
, obj->m_Time
|
||||
#endif // wxUSE_DATETIME
|
||||
);
|
||||
}
|
||||
|
||||
wxString wxMemoryFSHandlerBase::FindFirst(const wxString& url, int flags)
|
||||
{
|
||||
// Make sure to reset the find iterator, so that calling FindNext() doesn't
|
||||
// reuse its value from the last search that could well be invalid.
|
||||
m_findIter = m_Hash.end();
|
||||
|
||||
if ( (flags & wxDIR) && !(flags & wxFILE) )
|
||||
{
|
||||
// we only store files, not directories, so we don't risk finding
|
||||
// anything
|
||||
return wxString();
|
||||
}
|
||||
|
||||
const wxString spec = GetRightLocation(url);
|
||||
if ( spec.find_first_of("?*") == wxString::npos )
|
||||
{
|
||||
// simple case: there are no wildcard characters so we can return
|
||||
// either 0 or 1 results and we can find the potential match quickly
|
||||
return m_Hash.count(spec) ? url : wxString();
|
||||
}
|
||||
//else: deal with wildcards in FindNext()
|
||||
|
||||
m_findArgument = spec;
|
||||
m_findIter = m_Hash.begin();
|
||||
|
||||
return FindNext();
|
||||
}
|
||||
|
||||
wxString wxMemoryFSHandlerBase::FindNext()
|
||||
{
|
||||
while ( m_findIter != m_Hash.end() )
|
||||
{
|
||||
const wxString& path = m_findIter->first;
|
||||
|
||||
// advance m_findIter first as we need to do it anyhow, whether it
|
||||
// matches or not
|
||||
++m_findIter;
|
||||
|
||||
if ( path.Matches(m_findArgument) )
|
||||
return "memory:" + path;
|
||||
}
|
||||
|
||||
return wxString();
|
||||
}
|
||||
|
||||
bool wxMemoryFSHandlerBase::CheckDoesntExist(const wxString& filename)
|
||||
{
|
||||
if ( m_Hash.count(filename) )
|
||||
{
|
||||
wxLogError(_("Memory VFS already contains file '%s'!"), filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*static*/
|
||||
void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename,
|
||||
const wxString& textdata,
|
||||
const wxString& mimetype)
|
||||
{
|
||||
const wxCharBuffer buf(textdata.To8BitData());
|
||||
|
||||
AddFileWithMimeType(filename, buf.data(), buf.length(), mimetype);
|
||||
}
|
||||
|
||||
|
||||
/*static*/
|
||||
void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename,
|
||||
const void *binarydata, size_t size,
|
||||
const wxString& mimetype)
|
||||
{
|
||||
if ( !CheckDoesntExist(filename) )
|
||||
return;
|
||||
|
||||
m_Hash[filename] = new wxMemoryFSFile(binarydata, size, mimetype);
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void wxMemoryFSHandlerBase::AddFile(const wxString& filename,
|
||||
const wxString& textdata)
|
||||
{
|
||||
AddFileWithMimeType(filename, textdata, wxEmptyString);
|
||||
}
|
||||
|
||||
|
||||
/*static*/
|
||||
void wxMemoryFSHandlerBase::AddFile(const wxString& filename,
|
||||
const void *binarydata, size_t size)
|
||||
{
|
||||
AddFileWithMimeType(filename, binarydata, size, wxEmptyString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*static*/ void wxMemoryFSHandlerBase::RemoveFile(const wxString& filename)
|
||||
{
|
||||
wxMemoryFSHash::iterator i = m_Hash.find(filename);
|
||||
if ( i == m_Hash.end() )
|
||||
{
|
||||
wxLogError(_("Trying to remove file '%s' from memory VFS, "
|
||||
"but it is not loaded!"),
|
||||
filename);
|
||||
return;
|
||||
}
|
||||
|
||||
delete i->second;
|
||||
m_Hash.erase(i);
|
||||
}
|
||||
|
||||
#endif // wxUSE_BASE
|
||||
|
||||
#if wxUSE_GUI
|
||||
|
||||
#if wxUSE_IMAGE
|
||||
/*static*/ void
|
||||
wxMemoryFSHandler::AddFile(const wxString& filename,
|
||||
const wxImage& image,
|
||||
wxBitmapType type)
|
||||
{
|
||||
if ( !CheckDoesntExist(filename) )
|
||||
return;
|
||||
|
||||
wxMemoryOutputStream mems;
|
||||
if ( image.IsOk() && image.SaveFile(mems, type) )
|
||||
{
|
||||
m_Hash[filename] = new wxMemoryFSFile
|
||||
(
|
||||
mems,
|
||||
wxImage::FindHandler(type)->GetMimeType()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogError(_("Failed to store image '%s' to memory VFS!"), filename);
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
wxMemoryFSHandler::AddFile(const wxString& filename,
|
||||
const wxBitmap& bitmap,
|
||||
wxBitmapType type)
|
||||
{
|
||||
wxImage img = bitmap.ConvertToImage();
|
||||
AddFile(filename, img, type);
|
||||
}
|
||||
|
||||
#endif // wxUSE_IMAGE
|
||||
|
||||
#endif // wxUSE_GUI
|
||||
|
||||
|
||||
#endif // wxUSE_FILESYSTEM && wxUSE_FS_ZIP
|
||||
@@ -0,0 +1,326 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/fswatchercmn.cpp
|
||||
// Purpose: wxMswFileSystemWatcher
|
||||
// Author: Bartosz Bekier
|
||||
// Created: 2009-05-26
|
||||
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_FSWATCHER
|
||||
|
||||
#include "wx/fswatcher.h"
|
||||
#include "wx/private/fswatcher.h"
|
||||
|
||||
// ============================================================================
|
||||
// helpers
|
||||
// ============================================================================
|
||||
|
||||
wxDEFINE_EVENT(wxEVT_FSWATCHER, wxFileSystemWatcherEvent);
|
||||
|
||||
static wxString GetFSWEventChangeTypeName(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case wxFSW_EVENT_CREATE:
|
||||
return "CREATE";
|
||||
case wxFSW_EVENT_DELETE:
|
||||
return "DELETE";
|
||||
case wxFSW_EVENT_RENAME:
|
||||
return "RENAME";
|
||||
case wxFSW_EVENT_MODIFY:
|
||||
return "MODIFY";
|
||||
case wxFSW_EVENT_ACCESS:
|
||||
return "ACCESS";
|
||||
case wxFSW_EVENT_ATTRIB: // Currently this is wxGTK-only
|
||||
return "ATTRIBUTE";
|
||||
#ifdef wxHAS_INOTIFY
|
||||
case wxFSW_EVENT_UNMOUNT: // Currently this is wxGTK-only
|
||||
return "UNMOUNT";
|
||||
#endif
|
||||
case wxFSW_EVENT_WARNING:
|
||||
return "WARNING";
|
||||
case wxFSW_EVENT_ERROR:
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
// should never be reached!
|
||||
wxFAIL_MSG("Unknown change type");
|
||||
return "INVALID_TYPE";
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// wxFileSystemWatcherEvent implementation
|
||||
// ============================================================================
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxFileSystemWatcherEvent, wxEvent);
|
||||
|
||||
wxString wxFileSystemWatcherEvent::ToString() const
|
||||
{
|
||||
if (IsError())
|
||||
{
|
||||
return wxString::Format("FSW_EVT type=%d (%s) message='%s'", m_changeType,
|
||||
GetFSWEventChangeTypeName(m_changeType), GetErrorDescription());
|
||||
}
|
||||
return wxString::Format("FSW_EVT type=%d (%s) path='%s'", m_changeType,
|
||||
GetFSWEventChangeTypeName(m_changeType), GetPath().GetFullPath());
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// wxFileSystemWatcherEvent implementation
|
||||
// ============================================================================
|
||||
|
||||
wxFileSystemWatcherBase::wxFileSystemWatcherBase() :
|
||||
m_service(0), m_owner(this)
|
||||
{
|
||||
}
|
||||
|
||||
wxFileSystemWatcherBase::~wxFileSystemWatcherBase()
|
||||
{
|
||||
RemoveAll();
|
||||
delete m_service;
|
||||
}
|
||||
|
||||
bool wxFileSystemWatcherBase::Add(const wxFileName& path, int events)
|
||||
{
|
||||
wxFSWPathType type = wxFSWPath_None;
|
||||
if ( path.FileExists() )
|
||||
{
|
||||
type = wxFSWPath_File;
|
||||
}
|
||||
else if ( path.DirExists() )
|
||||
{
|
||||
type = wxFSWPath_Dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't overreact to being passed a non-existent item. It may have
|
||||
// only just been deleted, in which case doing nothing is correct
|
||||
wxLogTrace(wxTRACE_FSWATCHER,
|
||||
"Can't monitor non-existent path \"%s\" for changes.",
|
||||
path.GetFullPath());
|
||||
return false;
|
||||
}
|
||||
|
||||
return AddAny(path, events, type);
|
||||
}
|
||||
|
||||
bool
|
||||
wxFileSystemWatcherBase::AddAny(const wxFileName& path,
|
||||
int events,
|
||||
wxFSWPathType type,
|
||||
const wxString& filespec)
|
||||
{
|
||||
wxString canonical = GetCanonicalPath(path);
|
||||
if (canonical.IsEmpty())
|
||||
return false;
|
||||
|
||||
// Check if the patch isn't already being watched.
|
||||
wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
|
||||
if ( it == m_watches.end() )
|
||||
{
|
||||
// It isn't, so start watching it in a platform specific way:
|
||||
wxFSWatchInfo watch(canonical, events, type, filespec);
|
||||
if ( !m_service->Add(watch) )
|
||||
return false;
|
||||
|
||||
wxFSWatchInfoMap::value_type val(canonical, watch);
|
||||
m_watches.insert(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
wxFSWatchInfo& watch2 = it->second;
|
||||
const int count = watch2.IncRef();
|
||||
|
||||
wxLogTrace(wxTRACE_FSWATCHER,
|
||||
"'%s' is now watched %d times", canonical, count);
|
||||
|
||||
wxUnusedVar(count); // could be unused if debug tracing is disabled
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxFileSystemWatcherBase::Remove(const wxFileName& path)
|
||||
{
|
||||
// args validation & consistency checks
|
||||
wxString canonical = GetCanonicalPath(path);
|
||||
if (canonical.IsEmpty())
|
||||
return false;
|
||||
|
||||
wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
|
||||
wxCHECK_MSG(it != m_watches.end(), false,
|
||||
wxString::Format("Path '%s' is not watched", canonical));
|
||||
|
||||
// Decrement the watch's refcount and remove from watch-list if 0
|
||||
bool ret = true;
|
||||
wxFSWatchInfo& watch = it->second;
|
||||
if ( !watch.DecRef() )
|
||||
{
|
||||
// remove in a platform specific way
|
||||
ret = m_service->Remove(watch);
|
||||
|
||||
m_watches.erase(it);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events,
|
||||
const wxString& filespec)
|
||||
{
|
||||
if (!path.DirExists())
|
||||
return false;
|
||||
|
||||
// OPT could be optimised if we stored information about relationships
|
||||
// between paths
|
||||
class AddTraverser : public wxDirTraverser
|
||||
{
|
||||
public:
|
||||
AddTraverser(wxFileSystemWatcherBase* watcher, int events,
|
||||
const wxString& filespec) :
|
||||
m_watcher(watcher), m_events(events), m_filespec(filespec)
|
||||
{
|
||||
}
|
||||
|
||||
virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename)) wxOVERRIDE
|
||||
{
|
||||
// There is no need to watch individual files as we watch the
|
||||
// parent directory which will notify us about any changes in them.
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
virtual wxDirTraverseResult OnDir(const wxString& dirname) wxOVERRIDE
|
||||
{
|
||||
if ( m_watcher->AddAny(wxFileName::DirName(dirname),
|
||||
m_events, wxFSWPath_Tree, m_filespec) )
|
||||
{
|
||||
wxLogTrace(wxTRACE_FSWATCHER,
|
||||
"--- AddTree adding directory '%s' ---", dirname);
|
||||
}
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
private:
|
||||
wxFileSystemWatcherBase* m_watcher;
|
||||
int m_events;
|
||||
wxString m_filespec;
|
||||
};
|
||||
|
||||
wxDir dir(path.GetFullPath());
|
||||
// Prevent asserts or infinite loops in trees containing symlinks
|
||||
int flags = wxDIR_DIRS;
|
||||
if ( !path.ShouldFollowLink() )
|
||||
{
|
||||
flags |= wxDIR_NO_FOLLOW;
|
||||
}
|
||||
AddTraverser traverser(this, events, filespec);
|
||||
dir.Traverse(traverser, filespec, flags);
|
||||
|
||||
// Add the path itself explicitly as Traverse() doesn't return it.
|
||||
AddAny(path.GetPathWithSep(), events, wxFSWPath_Tree, filespec);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxFileSystemWatcherBase::RemoveTree(const wxFileName& path)
|
||||
{
|
||||
if (!path.DirExists())
|
||||
return false;
|
||||
|
||||
// OPT could be optimised if we stored information about relationships
|
||||
// between paths
|
||||
class RemoveTraverser : public wxDirTraverser
|
||||
{
|
||||
public:
|
||||
RemoveTraverser(wxFileSystemWatcherBase* watcher,
|
||||
const wxString& filespec) :
|
||||
m_watcher(watcher), m_filespec(filespec)
|
||||
{
|
||||
}
|
||||
|
||||
virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename)) wxOVERRIDE
|
||||
{
|
||||
// We never watch the individual files when watching the tree, so
|
||||
// nothing to do here.
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
virtual wxDirTraverseResult OnDir(const wxString& dirname) wxOVERRIDE
|
||||
{
|
||||
m_watcher->Remove(wxFileName::DirName(dirname));
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
private:
|
||||
wxFileSystemWatcherBase* m_watcher;
|
||||
wxString m_filespec;
|
||||
};
|
||||
|
||||
// If AddTree() used a filespec, we must use the same one
|
||||
wxString canonical = GetCanonicalPath(path);
|
||||
wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
|
||||
wxCHECK_MSG( it != m_watches.end(), false,
|
||||
wxString::Format("Path '%s' is not watched", canonical) );
|
||||
wxFSWatchInfo watch = it->second;
|
||||
const wxString filespec = watch.GetFilespec();
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
// When there's no filespec, the wxMSW AddTree() would have set a watch
|
||||
// on only the passed 'path'. We must therefore remove only this
|
||||
if (filespec.empty())
|
||||
{
|
||||
return Remove(path);
|
||||
}
|
||||
// Otherwise fall through to the generic implementation
|
||||
#endif // __WINDOWS__
|
||||
|
||||
wxDir dir(path.GetFullPath());
|
||||
// AddTree() might have used the wxDIR_NO_FOLLOW to prevent asserts or
|
||||
// infinite loops in trees containing symlinks. We need to do the same
|
||||
// or we'll try to remove unwatched items. Let's hope the caller used
|
||||
// the same ShouldFollowLink() setting as in AddTree()...
|
||||
int flags = wxDIR_DIRS;
|
||||
if ( !path.ShouldFollowLink() )
|
||||
{
|
||||
flags |= wxDIR_NO_FOLLOW;
|
||||
}
|
||||
RemoveTraverser traverser(this, filespec);
|
||||
dir.Traverse(traverser, filespec, flags);
|
||||
|
||||
// As in AddTree() above, handle the path itself explicitly.
|
||||
Remove(path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxFileSystemWatcherBase::RemoveAll()
|
||||
{
|
||||
const bool ret = m_service->RemoveAll();
|
||||
m_watches.clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wxFileSystemWatcherBase::GetWatchedPathsCount() const
|
||||
{
|
||||
return m_watches.size();
|
||||
}
|
||||
|
||||
int wxFileSystemWatcherBase::GetWatchedPaths(wxArrayString* paths) const
|
||||
{
|
||||
wxCHECK_MSG( paths != NULL, -1, "Null array passed to retrieve paths");
|
||||
|
||||
wxFSWatchInfoMap::const_iterator it = m_watches.begin();
|
||||
for ( ; it != m_watches.end(); ++it)
|
||||
{
|
||||
paths->push_back(it->first);
|
||||
}
|
||||
|
||||
return m_watches.size();
|
||||
}
|
||||
|
||||
#endif // wxUSE_FSWATCHER
|
||||
@@ -0,0 +1,390 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/geometry.cpp
|
||||
// Purpose: Common Geometry Classes
|
||||
// Author: Stefan Csomor
|
||||
// Modified by:
|
||||
// Created: 08/05/99
|
||||
// Copyright: (c) 1999 Stefan Csomor
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_GEOMETRY
|
||||
|
||||
#include "wx/geometry.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/log.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "wx/datstrm.h"
|
||||
|
||||
//
|
||||
// wxPoint2D
|
||||
//
|
||||
|
||||
//
|
||||
// wxRect2D
|
||||
//
|
||||
|
||||
// wxDouble version
|
||||
|
||||
// for the following calculations always remember
|
||||
// that the right and bottom edges are not part of a rect
|
||||
|
||||
bool wxRect2DDouble::Intersects( const wxRect2DDouble &rect ) const
|
||||
{
|
||||
wxDouble left,right,bottom,top;
|
||||
left = wxMax ( m_x , rect.m_x );
|
||||
right = wxMin ( m_x+m_width, rect.m_x + rect.m_width );
|
||||
top = wxMax ( m_y , rect.m_y );
|
||||
bottom = wxMin ( m_y+m_height, rect.m_y + rect.m_height );
|
||||
|
||||
if ( left < right && top < bottom )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxRect2DDouble::Intersect( const wxRect2DDouble &src1 , const wxRect2DDouble &src2 , wxRect2DDouble *dest )
|
||||
{
|
||||
wxDouble left,right,bottom,top;
|
||||
left = wxMax ( src1.m_x , src2.m_x );
|
||||
right = wxMin ( src1.m_x+src1.m_width, src2.m_x + src2.m_width );
|
||||
top = wxMax ( src1.m_y , src2.m_y );
|
||||
bottom = wxMin ( src1.m_y+src1.m_height, src2.m_y + src2.m_height );
|
||||
|
||||
if ( left < right && top < bottom )
|
||||
{
|
||||
dest->m_x = left;
|
||||
dest->m_y = top;
|
||||
dest->m_width = right - left;
|
||||
dest->m_height = bottom - top;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest->m_width = dest->m_height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void wxRect2DDouble::Union( const wxRect2DDouble &src1 , const wxRect2DDouble &src2 , wxRect2DDouble *dest )
|
||||
{
|
||||
wxDouble left,right,bottom,top;
|
||||
|
||||
left = wxMin ( src1.m_x , src2.m_x );
|
||||
right = wxMax ( src1.m_x+src1.m_width, src2.m_x + src2.m_width );
|
||||
top = wxMin ( src1.m_y , src2.m_y );
|
||||
bottom = wxMax ( src1.m_y+src1.m_height, src2.m_y + src2.m_height );
|
||||
|
||||
dest->m_x = left;
|
||||
dest->m_y = top;
|
||||
dest->m_width = right - left;
|
||||
dest->m_height = bottom - top;
|
||||
}
|
||||
|
||||
void wxRect2DDouble::Union( const wxPoint2DDouble &pt )
|
||||
{
|
||||
wxDouble x = pt.m_x;
|
||||
wxDouble y = pt.m_y;
|
||||
|
||||
if ( x < m_x )
|
||||
{
|
||||
SetLeft( x );
|
||||
}
|
||||
else if ( x < m_x + m_width )
|
||||
{
|
||||
// contained
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRight( x );
|
||||
}
|
||||
|
||||
if ( y < m_y )
|
||||
{
|
||||
SetTop( y );
|
||||
}
|
||||
else if ( y < m_y + m_height )
|
||||
{
|
||||
// contained
|
||||
}
|
||||
else
|
||||
{
|
||||
SetBottom( y );
|
||||
}
|
||||
}
|
||||
|
||||
void wxRect2DDouble::ConstrainTo( const wxRect2DDouble &rect )
|
||||
{
|
||||
if ( GetLeft() < rect.GetLeft() )
|
||||
SetLeft( rect.GetLeft() );
|
||||
|
||||
if ( GetRight() > rect.GetRight() )
|
||||
SetRight( rect.GetRight() );
|
||||
|
||||
if ( GetBottom() > rect.GetBottom() )
|
||||
SetBottom( rect.GetBottom() );
|
||||
|
||||
if ( GetTop() < rect.GetTop() )
|
||||
SetTop( rect.GetTop() );
|
||||
}
|
||||
|
||||
// integer version
|
||||
|
||||
// for the following calculations always remember
|
||||
// that the right and bottom edges are not part of a rect
|
||||
|
||||
// wxPoint2D
|
||||
|
||||
#if wxUSE_STREAMS
|
||||
void wxPoint2DInt::WriteTo( wxDataOutputStream &stream ) const
|
||||
{
|
||||
stream.Write32( m_x );
|
||||
stream.Write32( m_y );
|
||||
}
|
||||
|
||||
void wxPoint2DInt::ReadFrom( wxDataInputStream &stream )
|
||||
{
|
||||
m_x = stream.Read32();
|
||||
m_y = stream.Read32();
|
||||
}
|
||||
#endif // wxUSE_STREAMS
|
||||
|
||||
wxDouble wxPoint2DInt::GetVectorAngle() const
|
||||
{
|
||||
if ( m_x == 0 )
|
||||
{
|
||||
if ( m_y >= 0 )
|
||||
return 90;
|
||||
else
|
||||
return 270;
|
||||
}
|
||||
if ( m_y == 0 )
|
||||
{
|
||||
if ( m_x >= 0 )
|
||||
return 0;
|
||||
else
|
||||
return 180;
|
||||
}
|
||||
|
||||
wxDouble deg = wxRadToDeg(atan2( (double)m_y , (double)m_x ));
|
||||
if ( deg < 0 )
|
||||
{
|
||||
deg += 360;
|
||||
}
|
||||
return deg;
|
||||
}
|
||||
|
||||
|
||||
void wxPoint2DInt::SetVectorAngle( wxDouble degrees )
|
||||
{
|
||||
wxDouble length = GetVectorLength();
|
||||
double rad = wxDegToRad(degrees);
|
||||
m_x = (int)(length * cos(rad));
|
||||
m_y = (int)(length * sin(rad));
|
||||
}
|
||||
|
||||
wxDouble wxPoint2DDouble::GetVectorAngle() const
|
||||
{
|
||||
if ( wxIsNullDouble(m_x) )
|
||||
{
|
||||
if ( m_y >= 0 )
|
||||
return 90;
|
||||
else
|
||||
return 270;
|
||||
}
|
||||
if ( wxIsNullDouble(m_y) )
|
||||
{
|
||||
if ( m_x >= 0 )
|
||||
return 0;
|
||||
else
|
||||
return 180;
|
||||
}
|
||||
wxDouble deg = wxRadToDeg(atan2( m_y , m_x ));
|
||||
if ( deg < 0 )
|
||||
{
|
||||
deg += 360;
|
||||
}
|
||||
return deg;
|
||||
}
|
||||
|
||||
void wxPoint2DDouble::SetVectorAngle( wxDouble degrees )
|
||||
{
|
||||
wxDouble length = GetVectorLength();
|
||||
double rad = wxDegToRad(degrees);
|
||||
m_x = length * cos(rad);
|
||||
m_y = length * sin(rad);
|
||||
}
|
||||
|
||||
// wxRect2D
|
||||
|
||||
bool wxRect2DInt::Intersects( const wxRect2DInt &rect ) const
|
||||
{
|
||||
wxInt32 left,right,bottom,top;
|
||||
left = wxMax ( m_x , rect.m_x );
|
||||
right = wxMin ( m_x+m_width, rect.m_x + rect.m_width );
|
||||
top = wxMax ( m_y , rect.m_y );
|
||||
bottom = wxMin ( m_y+m_height, rect.m_y + rect.m_height );
|
||||
|
||||
if ( left < right && top < bottom )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxRect2DInt::Intersect( const wxRect2DInt &src1 , const wxRect2DInt &src2 , wxRect2DInt *dest )
|
||||
{
|
||||
wxInt32 left,right,bottom,top;
|
||||
left = wxMax ( src1.m_x , src2.m_x );
|
||||
right = wxMin ( src1.m_x+src1.m_width, src2.m_x + src2.m_width );
|
||||
top = wxMax ( src1.m_y , src2.m_y );
|
||||
bottom = wxMin ( src1.m_y+src1.m_height, src2.m_y + src2.m_height );
|
||||
|
||||
if ( left < right && top < bottom )
|
||||
{
|
||||
dest->m_x = left;
|
||||
dest->m_y = top;
|
||||
dest->m_width = right - left;
|
||||
dest->m_height = bottom - top;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest->m_width = dest->m_height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void wxRect2DInt::Union( const wxRect2DInt &src1 , const wxRect2DInt &src2 , wxRect2DInt *dest )
|
||||
{
|
||||
wxInt32 left,right,bottom,top;
|
||||
|
||||
left = wxMin ( src1.m_x , src2.m_x );
|
||||
right = wxMax ( src1.m_x+src1.m_width, src2.m_x + src2.m_width );
|
||||
top = wxMin ( src1.m_y , src2.m_y );
|
||||
bottom = wxMax ( src1.m_y+src1.m_height, src2.m_y + src2.m_height );
|
||||
|
||||
dest->m_x = left;
|
||||
dest->m_y = top;
|
||||
dest->m_width = right - left;
|
||||
dest->m_height = bottom - top;
|
||||
}
|
||||
|
||||
void wxRect2DInt::Union( const wxPoint2DInt &pt )
|
||||
{
|
||||
wxInt32 x = pt.m_x;
|
||||
wxInt32 y = pt.m_y;
|
||||
|
||||
if ( x < m_x )
|
||||
{
|
||||
SetLeft( x );
|
||||
}
|
||||
else if ( x < m_x + m_width )
|
||||
{
|
||||
// contained
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRight( x );
|
||||
}
|
||||
|
||||
if ( y < m_y )
|
||||
{
|
||||
SetTop( y );
|
||||
}
|
||||
else if ( y < m_y + m_height )
|
||||
{
|
||||
// contained
|
||||
}
|
||||
else
|
||||
{
|
||||
SetBottom( y );
|
||||
}
|
||||
}
|
||||
|
||||
void wxRect2DInt::ConstrainTo( const wxRect2DInt &rect )
|
||||
{
|
||||
if ( GetLeft() < rect.GetLeft() )
|
||||
SetLeft( rect.GetLeft() );
|
||||
|
||||
if ( GetRight() > rect.GetRight() )
|
||||
SetRight( rect.GetRight() );
|
||||
|
||||
if ( GetBottom() > rect.GetBottom() )
|
||||
SetBottom( rect.GetBottom() );
|
||||
|
||||
if ( GetTop() < rect.GetTop() )
|
||||
SetTop( rect.GetTop() );
|
||||
}
|
||||
|
||||
#if wxUSE_STREAMS
|
||||
void wxRect2DInt::WriteTo( wxDataOutputStream &stream ) const
|
||||
{
|
||||
stream.Write32( m_x );
|
||||
stream.Write32( m_y );
|
||||
stream.Write32( m_width );
|
||||
stream.Write32( m_height );
|
||||
}
|
||||
|
||||
void wxRect2DInt::ReadFrom( wxDataInputStream &stream )
|
||||
{
|
||||
m_x = stream.Read32();
|
||||
m_y = stream.Read32();
|
||||
m_width = stream.Read32();
|
||||
m_height = stream.Read32();
|
||||
}
|
||||
#endif // wxUSE_STREAMS
|
||||
|
||||
|
||||
// wxTransform2D
|
||||
|
||||
void wxTransform2D::Transform( wxRect2DInt* r ) const
|
||||
{
|
||||
wxPoint2DInt a = r->GetLeftTop(), b = r->GetRightBottom();
|
||||
Transform( &a );
|
||||
Transform( &b );
|
||||
*r = wxRect2DInt( a, b );
|
||||
}
|
||||
|
||||
wxPoint2DInt wxTransform2D::Transform( const wxPoint2DInt &pt ) const
|
||||
{
|
||||
wxPoint2DInt res = pt;
|
||||
Transform( &res );
|
||||
return res;
|
||||
}
|
||||
|
||||
wxRect2DInt wxTransform2D::Transform( const wxRect2DInt &r ) const
|
||||
{
|
||||
wxRect2DInt res = r;
|
||||
Transform( &res );
|
||||
return res;
|
||||
}
|
||||
|
||||
void wxTransform2D::InverseTransform( wxRect2DInt* r ) const
|
||||
{
|
||||
wxPoint2DInt a = r->GetLeftTop(), b = r->GetRightBottom();
|
||||
InverseTransform( &a );
|
||||
InverseTransform( &b );
|
||||
*r = wxRect2DInt( a , b );
|
||||
}
|
||||
|
||||
wxPoint2DInt wxTransform2D::InverseTransform( const wxPoint2DInt &pt ) const
|
||||
{
|
||||
wxPoint2DInt res = pt;
|
||||
InverseTransform( &res );
|
||||
return res;
|
||||
}
|
||||
|
||||
wxRect2DInt wxTransform2D::InverseTransform( const wxRect2DInt &r ) const
|
||||
{
|
||||
wxRect2DInt res = r;
|
||||
InverseTransform( &res );
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // wxUSE_GEOMETRY
|
||||
@@ -0,0 +1,379 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/hash.cpp
|
||||
// Purpose: wxHashTable implementation
|
||||
// Author: Julian Smart
|
||||
// Modified by: VZ at 25.02.00: type safe hashes with WX_DECLARE_HASH()
|
||||
// Created: 01/02/97
|
||||
// Copyright: (c) Julian Smart
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/hash.h"
|
||||
#include "wx/object.h"
|
||||
#endif
|
||||
|
||||
wxHashTableBase_Node::wxHashTableBase_Node( long key, void* value,
|
||||
wxHashTableBase* table )
|
||||
: m_value( value ), m_hashPtr( table )
|
||||
{
|
||||
m_key.integer = key;
|
||||
}
|
||||
|
||||
wxHashTableBase_Node::wxHashTableBase_Node( const wxString& key, void* value,
|
||||
wxHashTableBase* table )
|
||||
: m_value( value ), m_hashPtr( table )
|
||||
{
|
||||
m_key.string = new wxString(key);
|
||||
}
|
||||
|
||||
wxHashTableBase_Node::~wxHashTableBase_Node()
|
||||
{
|
||||
if( m_hashPtr ) m_hashPtr->DoRemoveNode( this );
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
wxHashTableBase::wxHashTableBase()
|
||||
: m_size( 0 ), m_count( 0 ), m_table( NULL ), m_keyType( wxKEY_NONE ),
|
||||
m_deleteContents( false )
|
||||
{
|
||||
}
|
||||
|
||||
void wxHashTableBase::Create( wxKeyType keyType, size_t size )
|
||||
{
|
||||
m_keyType = keyType;
|
||||
m_size = size;
|
||||
m_table = new wxHashTableBase_Node*[ m_size ];
|
||||
|
||||
for( size_t i = 0; i < m_size; ++i )
|
||||
m_table[i] = NULL;
|
||||
}
|
||||
|
||||
void wxHashTableBase::Clear()
|
||||
{
|
||||
for( size_t i = 0; i < m_size; ++i )
|
||||
{
|
||||
Node* end = m_table[i];
|
||||
|
||||
if( end == NULL )
|
||||
continue;
|
||||
|
||||
Node *curr, *next = end->GetNext();
|
||||
|
||||
do
|
||||
{
|
||||
curr = next;
|
||||
next = curr->GetNext();
|
||||
|
||||
DoDestroyNode( curr );
|
||||
|
||||
delete curr;
|
||||
}
|
||||
while( curr != end );
|
||||
|
||||
m_table[i] = NULL;
|
||||
}
|
||||
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
void wxHashTableBase::DoRemoveNode( wxHashTableBase_Node* node )
|
||||
{
|
||||
size_t bucket = ( m_keyType == wxKEY_INTEGER ?
|
||||
node->m_key.integer :
|
||||
MakeKey( *node->m_key.string ) ) % m_size;
|
||||
|
||||
if( node->GetNext() == node )
|
||||
{
|
||||
// single-node chain (common case)
|
||||
m_table[bucket] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
Node *start = m_table[bucket], *curr;
|
||||
Node* prev = start;
|
||||
|
||||
for( curr = prev->GetNext(); curr != node;
|
||||
prev = curr, curr = curr->GetNext() ) ;
|
||||
|
||||
DoUnlinkNode( bucket, node, prev );
|
||||
}
|
||||
|
||||
DoDestroyNode( node );
|
||||
}
|
||||
|
||||
void wxHashTableBase::DoDestroyNode( wxHashTableBase_Node* node )
|
||||
{
|
||||
// if it is called from DoRemoveNode, node has already been
|
||||
// removed, from other places it does not matter
|
||||
node->m_hashPtr = NULL;
|
||||
|
||||
if( m_keyType == wxKEY_STRING )
|
||||
delete node->m_key.string;
|
||||
if( m_deleteContents )
|
||||
DoDeleteContents( node );
|
||||
}
|
||||
|
||||
void wxHashTableBase::Destroy()
|
||||
{
|
||||
Clear();
|
||||
|
||||
wxDELETEA(m_table);
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
void wxHashTableBase::DoInsertNode( size_t bucket, wxHashTableBase_Node* node )
|
||||
{
|
||||
if( m_table[bucket] == NULL )
|
||||
{
|
||||
m_table[bucket] = node->m_next = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
Node *prev = m_table[bucket];
|
||||
Node *next = prev->m_next;
|
||||
|
||||
prev->m_next = node;
|
||||
node->m_next = next;
|
||||
m_table[bucket] = node;
|
||||
}
|
||||
|
||||
++m_count;
|
||||
}
|
||||
|
||||
void wxHashTableBase::DoPut( long key, long hash, void* data )
|
||||
{
|
||||
wxASSERT( m_keyType == wxKEY_INTEGER );
|
||||
|
||||
size_t bucket = size_t(hash) % m_size;
|
||||
Node* node = new wxHashTableBase_Node( key, data, this );
|
||||
|
||||
DoInsertNode( bucket, node );
|
||||
}
|
||||
|
||||
void wxHashTableBase::DoPut( const wxString& key, long hash, void* data )
|
||||
{
|
||||
wxASSERT( m_keyType == wxKEY_STRING );
|
||||
|
||||
size_t bucket = size_t(hash) % m_size;
|
||||
Node* node = new wxHashTableBase_Node( key, data, this );
|
||||
|
||||
DoInsertNode( bucket, node );
|
||||
}
|
||||
|
||||
void* wxHashTableBase::DoGet( long key, long hash ) const
|
||||
{
|
||||
wxASSERT( m_keyType == wxKEY_INTEGER );
|
||||
|
||||
size_t bucket = size_t(hash) % m_size;
|
||||
|
||||
if( m_table[bucket] == NULL )
|
||||
return NULL;
|
||||
|
||||
Node *first = m_table[bucket]->GetNext(),
|
||||
*curr = first;
|
||||
|
||||
do
|
||||
{
|
||||
if( curr->m_key.integer == key )
|
||||
return curr->m_value;
|
||||
|
||||
curr = curr->GetNext();
|
||||
}
|
||||
while( curr != first );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* wxHashTableBase::DoGet( const wxString& key, long hash ) const
|
||||
{
|
||||
wxASSERT( m_keyType == wxKEY_STRING );
|
||||
|
||||
size_t bucket = size_t(hash) % m_size;
|
||||
|
||||
if( m_table[bucket] == NULL )
|
||||
return NULL;
|
||||
|
||||
Node *first = m_table[bucket]->GetNext(),
|
||||
*curr = first;
|
||||
|
||||
do
|
||||
{
|
||||
if( *curr->m_key.string == key )
|
||||
return curr->m_value;
|
||||
|
||||
curr = curr->GetNext();
|
||||
}
|
||||
while( curr != first );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void wxHashTableBase::DoUnlinkNode( size_t bucket, wxHashTableBase_Node* node,
|
||||
wxHashTableBase_Node* prev )
|
||||
{
|
||||
if( node == m_table[bucket] )
|
||||
m_table[bucket] = prev;
|
||||
|
||||
if( prev == node && prev == node->GetNext() )
|
||||
m_table[bucket] = NULL;
|
||||
else
|
||||
prev->m_next = node->m_next;
|
||||
|
||||
DoDestroyNode( node );
|
||||
--m_count;
|
||||
}
|
||||
|
||||
void* wxHashTableBase::DoDelete( long key, long hash )
|
||||
{
|
||||
wxASSERT( m_keyType == wxKEY_INTEGER );
|
||||
|
||||
size_t bucket = size_t(hash) % m_size;
|
||||
|
||||
if( m_table[bucket] == NULL )
|
||||
return NULL;
|
||||
|
||||
Node *first = m_table[bucket]->GetNext(),
|
||||
*curr = first,
|
||||
*prev = m_table[bucket];
|
||||
|
||||
do
|
||||
{
|
||||
if( curr->m_key.integer == key )
|
||||
{
|
||||
void* retval = curr->m_value;
|
||||
curr->m_value = NULL;
|
||||
|
||||
DoUnlinkNode( bucket, curr, prev );
|
||||
delete curr;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
curr = curr->GetNext();
|
||||
}
|
||||
while( curr != first );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* wxHashTableBase::DoDelete( const wxString& key, long hash )
|
||||
{
|
||||
wxASSERT( m_keyType == wxKEY_STRING );
|
||||
|
||||
size_t bucket = size_t(hash) % m_size;
|
||||
|
||||
if( m_table[bucket] == NULL )
|
||||
return NULL;
|
||||
|
||||
Node *first = m_table[bucket]->GetNext(),
|
||||
*curr = first,
|
||||
*prev = m_table[bucket];
|
||||
|
||||
do
|
||||
{
|
||||
if( *curr->m_key.string == key )
|
||||
{
|
||||
void* retval = curr->m_value;
|
||||
curr->m_value = NULL;
|
||||
|
||||
DoUnlinkNode( bucket, curr, prev );
|
||||
delete curr;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
curr = curr->GetNext();
|
||||
}
|
||||
while( curr != first );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
long wxHashTableBase::MakeKey( const wxString& str )
|
||||
{
|
||||
long int_key = 0;
|
||||
|
||||
const wxStringCharType *p = str.wx_str();
|
||||
while( *p )
|
||||
int_key += *p++;
|
||||
|
||||
return int_key;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxHashTable
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxHashTable::wxHashTable( const wxHashTable& table )
|
||||
: wxHashTableBase()
|
||||
{
|
||||
DoCopy( table );
|
||||
}
|
||||
|
||||
const wxHashTable& wxHashTable::operator=( const wxHashTable& table )
|
||||
{
|
||||
Destroy();
|
||||
DoCopy( table );
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void wxHashTable::DoCopy( const wxHashTable& WXUNUSED(table) )
|
||||
{
|
||||
Create( m_keyType, m_size );
|
||||
|
||||
wxFAIL;
|
||||
}
|
||||
|
||||
void wxHashTable::DoDeleteContents( wxHashTableBase_Node* node )
|
||||
{
|
||||
delete ((wxHashTable_Node*)node)->GetData();
|
||||
}
|
||||
|
||||
void wxHashTable::GetNextNode( size_t bucketStart )
|
||||
{
|
||||
for( size_t i = bucketStart; i < m_size; ++i )
|
||||
{
|
||||
if( m_table[i] != NULL )
|
||||
{
|
||||
m_curr = ((Node*)m_table[i])->GetNext();
|
||||
m_currBucket = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_curr = NULL;
|
||||
m_currBucket = 0;
|
||||
}
|
||||
|
||||
wxHashTable::Node* wxHashTable::Next()
|
||||
{
|
||||
if( m_curr == NULL )
|
||||
GetNextNode( 0 );
|
||||
else
|
||||
{
|
||||
m_curr = m_curr->GetNext();
|
||||
|
||||
if( m_curr == ( (Node*)m_table[m_currBucket] )->GetNext() )
|
||||
GetNextNode( m_currBucket + 1 );
|
||||
}
|
||||
|
||||
return m_curr;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/hashmap.cpp
|
||||
// Purpose: wxHashMap implementation
|
||||
// Author: Mattia Barbon
|
||||
// Modified by:
|
||||
// Created: 29/01/2002
|
||||
// Copyright: (c) Mattia Barbon
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/hashmap.h"
|
||||
|
||||
/* FYI: This is the "One-at-a-Time" algorithm by Bob Jenkins */
|
||||
/* from requirements by Colin Plumb. */
|
||||
/* (http://burtleburtle.net/bob/hash/doobs.html) */
|
||||
/* adapted from Perl sources ( hv.h ) */
|
||||
template<typename T>
|
||||
static unsigned long DoStringHash(T *k)
|
||||
{
|
||||
unsigned long hash = 0;
|
||||
|
||||
while( *k )
|
||||
{
|
||||
hash += *k++;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
|
||||
return hash + (hash << 15);
|
||||
}
|
||||
|
||||
unsigned long wxStringHash::stringHash( const char* k )
|
||||
{ return DoStringHash(k); }
|
||||
|
||||
unsigned long wxStringHash::stringHash( const wchar_t* k )
|
||||
{ return DoStringHash(k); }
|
||||
|
||||
|
||||
#ifdef wxNEEDS_WX_HASH_MAP
|
||||
|
||||
/* from SGI STL */
|
||||
const unsigned long _wxHashTableBase2::ms_primes[prime_count] =
|
||||
{
|
||||
7ul, 13ul, 29ul,
|
||||
53ul, 97ul, 193ul, 389ul, 769ul,
|
||||
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
|
||||
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
|
||||
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
|
||||
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
|
||||
1610612741ul, 3221225473ul, 4294967291ul
|
||||
};
|
||||
|
||||
unsigned long _wxHashTableBase2::GetNextPrime( unsigned long n )
|
||||
{
|
||||
const unsigned long* ptr = &ms_primes[0];
|
||||
for( size_t i = 0; i < prime_count; ++i, ++ptr )
|
||||
{
|
||||
if( n < *ptr )
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
/* someone might try to alloc a 2^32-element hash table */
|
||||
wxFAIL_MSG( wxT("hash table too big?") );
|
||||
|
||||
/* quiet warning */
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long _wxHashTableBase2::GetPreviousPrime( unsigned long n )
|
||||
{
|
||||
const unsigned long* ptr = &ms_primes[prime_count - 1];
|
||||
|
||||
for( size_t i = 0; i < prime_count; ++i, --ptr )
|
||||
{
|
||||
if( n > *ptr )
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
/* quiet warning */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void _wxHashTableBase2::DeleteNodes( size_t buckets,
|
||||
_wxHashTable_NodeBase** table,
|
||||
NodeDtor dtor )
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for( i = 0; i < buckets; ++i )
|
||||
{
|
||||
_wxHashTable_NodeBase* node = table[i];
|
||||
_wxHashTable_NodeBase* tmp;
|
||||
|
||||
while( node )
|
||||
{
|
||||
tmp = node->m_next;
|
||||
dtor( node );
|
||||
node = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
memset( table, 0, buckets * sizeof(void*) );
|
||||
}
|
||||
|
||||
void _wxHashTableBase2::CopyHashTable( _wxHashTable_NodeBase** srcTable,
|
||||
size_t srcBuckets,
|
||||
_wxHashTableBase2* dst,
|
||||
_wxHashTable_NodeBase** dstTable,
|
||||
BucketFromNode func, ProcessNode proc )
|
||||
{
|
||||
for( size_t i = 0; i < srcBuckets; ++i )
|
||||
{
|
||||
_wxHashTable_NodeBase* nextnode;
|
||||
|
||||
for( _wxHashTable_NodeBase* node = srcTable[i]; node; node = nextnode )
|
||||
{
|
||||
size_t bucket = func( dst, node );
|
||||
|
||||
nextnode = node->m_next;
|
||||
_wxHashTable_NodeBase* newnode = proc( node );
|
||||
newnode->m_next = dstTable[bucket];
|
||||
dstTable[bucket] = newnode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_wxHashTable_NodeBase* _wxHashTableBase2::DummyProcessNode(_wxHashTable_NodeBase* node)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
#endif // wxNEEDS_WX_HASH_MAP
|
||||
@@ -0,0 +1,567 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/init.cpp
|
||||
// Purpose: initialisation for the library
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 04.10.99
|
||||
// Copyright: (c) Vadim Zeitlin
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/app.h"
|
||||
#include "wx/filefn.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/module.h"
|
||||
#endif
|
||||
|
||||
#include "wx/init.h"
|
||||
#include "wx/thread.h"
|
||||
|
||||
#include "wx/scopedptr.h"
|
||||
#include "wx/except.h"
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
#include "wx/msw/private.h"
|
||||
#include "wx/msw/msvcrt.h"
|
||||
|
||||
#ifdef wxCrtSetDbgFlag
|
||||
static struct EnableMemLeakChecking
|
||||
{
|
||||
EnableMemLeakChecking()
|
||||
{
|
||||
// check for memory leaks on program exit (another useful flag
|
||||
// is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free deallocated
|
||||
// memory which may be used to simulate low-memory condition)
|
||||
wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
|
||||
}
|
||||
} gs_enableLeakChecks;
|
||||
#endif // wxCrtSetDbgFlag
|
||||
#endif // __WINDOWS__
|
||||
|
||||
#if wxUSE_UNICODE && defined(__WXOSX__)
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// private classes
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// we need a dummy app object if the user doesn't want to create a real one
|
||||
class wxDummyConsoleApp : public wxAppConsole
|
||||
{
|
||||
public:
|
||||
wxDummyConsoleApp() { }
|
||||
|
||||
virtual int OnRun() wxOVERRIDE { wxFAIL_MSG( wxT("unreachable code") ); return 0; }
|
||||
virtual bool DoYield(bool, long) { return true; }
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxDummyConsoleApp);
|
||||
};
|
||||
|
||||
// we need a special kind of auto pointer to wxApp which not only deletes the
|
||||
// pointer it holds in its dtor but also resets the global application pointer
|
||||
wxDECLARE_SCOPED_PTR(wxAppConsole, wxAppPtrBase)
|
||||
wxDEFINE_SCOPED_PTR(wxAppConsole, wxAppPtrBase)
|
||||
|
||||
class wxAppPtr : public wxAppPtrBase
|
||||
{
|
||||
public:
|
||||
explicit wxAppPtr(wxAppConsole *ptr = NULL) : wxAppPtrBase(ptr) { }
|
||||
~wxAppPtr()
|
||||
{
|
||||
if ( get() )
|
||||
{
|
||||
// the pointer is going to be deleted in the base class dtor, don't
|
||||
// leave the dangling pointer!
|
||||
wxApp::SetInstance(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void Set(wxAppConsole *ptr)
|
||||
{
|
||||
reset(ptr);
|
||||
|
||||
wxApp::SetInstance(ptr);
|
||||
}
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxAppPtr);
|
||||
};
|
||||
|
||||
// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
|
||||
// fails
|
||||
class wxCallAppCleanup
|
||||
{
|
||||
public:
|
||||
wxCallAppCleanup(wxAppConsole *app) : m_app(app) { }
|
||||
~wxCallAppCleanup() { if ( m_app ) m_app->CleanUp(); }
|
||||
|
||||
void Dismiss() { m_app = NULL; }
|
||||
|
||||
private:
|
||||
wxAppConsole *m_app;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// private functions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// suppress warnings about unused variables
|
||||
static inline void Use(void *) { }
|
||||
|
||||
#define WX_SUPPRESS_UNUSED_WARN(x) Use(&x)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// initialization data
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static struct InitData
|
||||
{
|
||||
InitData()
|
||||
{
|
||||
nInitCount = 0;
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
argc = argcOrig = 0;
|
||||
// argv = argvOrig = NULL; -- not even really needed
|
||||
#endif // wxUSE_UNICODE
|
||||
}
|
||||
|
||||
// critical section protecting this struct
|
||||
wxCRIT_SECT_DECLARE_MEMBER(csInit);
|
||||
|
||||
// number of times wxInitialize() was called minus the number of times
|
||||
// wxUninitialize() was
|
||||
size_t nInitCount;
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
int argc;
|
||||
|
||||
// if we receive the command line arguments as ASCII and have to convert
|
||||
// them to Unicode ourselves (this is the case under Unix but not Windows,
|
||||
// for example), we remember the converted argv here because we'll have to
|
||||
// free it when doing cleanup to avoid memory leaks
|
||||
wchar_t **argv;
|
||||
|
||||
// we also need to keep two copies, one passed to other functions, and one
|
||||
// unmodified original; somebody may modify the former, so we need to have
|
||||
// the latter to be able to free everything correctly
|
||||
int argcOrig;
|
||||
wchar_t **argvOrig;
|
||||
#endif // wxUSE_UNICODE
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(InitData);
|
||||
} gs_initData;
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// command line arguments ANSI -> Unicode conversion
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
|
||||
static void ConvertArgsToUnicode(int argc, char **argv)
|
||||
{
|
||||
gs_initData.argvOrig = new wchar_t *[argc + 1];
|
||||
gs_initData.argv = new wchar_t *[argc + 1];
|
||||
|
||||
int wargc = 0;
|
||||
for ( int i = 0; i < argc; i++ )
|
||||
{
|
||||
#ifdef __DARWIN__
|
||||
wxWCharBuffer buf(wxConvFileName->cMB2WX(argv[i]));
|
||||
#else
|
||||
wxWCharBuffer buf(wxConvLocal.cMB2WX(argv[i]));
|
||||
#endif
|
||||
if ( !buf )
|
||||
{
|
||||
wxLogWarning(_("Command line argument %d couldn't be converted to Unicode and will be ignored."),
|
||||
i);
|
||||
}
|
||||
else // converted ok
|
||||
{
|
||||
gs_initData.argvOrig[wargc] = gs_initData.argv[wargc] = wxStrdup(buf);
|
||||
wargc++;
|
||||
}
|
||||
}
|
||||
|
||||
gs_initData.argcOrig = gs_initData.argc = wargc;
|
||||
gs_initData.argvOrig[wargc] =gs_initData.argv[wargc] = NULL;
|
||||
}
|
||||
|
||||
static void FreeConvertedArgs()
|
||||
{
|
||||
if ( gs_initData.argvOrig )
|
||||
{
|
||||
for ( int i = 0; i < gs_initData.argcOrig; i++ )
|
||||
{
|
||||
free(gs_initData.argvOrig[i]);
|
||||
// gs_initData.argv[i] normally points to the same data
|
||||
}
|
||||
|
||||
wxDELETEA(gs_initData.argvOrig);
|
||||
wxDELETEA(gs_initData.argv);
|
||||
gs_initData.argcOrig = gs_initData.argc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_UNICODE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// start up
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// initialization which is always done (not customizable) before wxApp creation
|
||||
static bool DoCommonPreInit()
|
||||
{
|
||||
#if wxUSE_UNICODE && defined(__WXOSX__)
|
||||
// In OS X and iOS, wchar_t CRT functions convert to char* and fail under
|
||||
// some locales. The safest fix is to set LC_CTYPE to UTF-8 to ensure that
|
||||
// they can handle any input.
|
||||
//
|
||||
// Note that this must be done for any app, Cocoa or console, whether or
|
||||
// not it uses wxLocale.
|
||||
//
|
||||
// See https://stackoverflow.com/questions/11713745/why-does-the-printf-family-of-functions-care-about-locale
|
||||
setlocale(LC_CTYPE, "UTF-8");
|
||||
#endif // wxUSE_UNICODE && defined(__WXOSX__)
|
||||
|
||||
#if wxUSE_LOG
|
||||
// Reset logging in case we were cleaned up and are being reinitialized.
|
||||
wxLog::DoCreateOnDemand();
|
||||
|
||||
// force wxLog to create a log target now: we do it because wxTheApp
|
||||
// doesn't exist yet so wxLog will create a special log target which is
|
||||
// safe to use even when the GUI is not available while without this call
|
||||
// we could create wxApp in wxEntryStart() below, then log an error about
|
||||
// e.g. failure to establish connection to the X server and wxLog would
|
||||
// send it to wxLogGui (because wxTheApp does exist already) which, of
|
||||
// course, can't be used in this case
|
||||
//
|
||||
// notice also that this does nothing if the user had set up a custom log
|
||||
// target before -- which is fine as we want to give him this possibility
|
||||
// (as it's impossible to override logging by overriding wxAppTraits::
|
||||
// CreateLogTarget() before wxApp is created) and we just assume he knows
|
||||
// what he is doing
|
||||
wxLog::GetActiveTarget();
|
||||
#endif // wxUSE_LOG
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
// GUI applications obtain HINSTANCE in their WinMain() but we also need to
|
||||
// initialize the global wxhInstance variable for the console programs as
|
||||
// they may need it too, so set it here if it wasn't done yet
|
||||
if ( !wxGetInstance() )
|
||||
{
|
||||
wxSetInstance(::GetModuleHandle(NULL));
|
||||
}
|
||||
#endif // __WINDOWS__
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// non customizable initialization done after wxApp creation and initialization
|
||||
static bool DoCommonPostInit()
|
||||
{
|
||||
wxModule::RegisterModules();
|
||||
|
||||
if ( !wxModule::InitializeModules() )
|
||||
{
|
||||
wxLogError(_("Initialization failed in post init, aborting."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxEntryStart(int& argc, wxChar **argv)
|
||||
{
|
||||
// do minimal, always necessary, initialization
|
||||
// --------------------------------------------
|
||||
|
||||
// initialize wxRTTI
|
||||
if ( !DoCommonPreInit() )
|
||||
return false;
|
||||
|
||||
|
||||
// first of all, we need an application object
|
||||
// -------------------------------------------
|
||||
|
||||
// the user might have already created it himself somehow
|
||||
wxAppPtr app(wxTheApp);
|
||||
if ( !app.get() )
|
||||
{
|
||||
// if not, he might have used wxIMPLEMENT_APP() to give us a
|
||||
// function to create it
|
||||
wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction();
|
||||
|
||||
if ( fnCreate )
|
||||
{
|
||||
// he did, try to create the custom wxApp object
|
||||
app.Set((*fnCreate)());
|
||||
}
|
||||
}
|
||||
|
||||
if ( !app.get() )
|
||||
{
|
||||
// either wxIMPLEMENT_APP() was not used at all or it failed -- in
|
||||
// any case we still need something
|
||||
app.Set(new wxDummyConsoleApp);
|
||||
}
|
||||
|
||||
|
||||
// wxApp initialization: this can be customized
|
||||
// --------------------------------------------
|
||||
|
||||
if ( !app->Initialize(argc, argv) )
|
||||
return false;
|
||||
|
||||
// remember, possibly modified (e.g. due to removal of toolkit-specific
|
||||
// parameters), command line arguments in member variables
|
||||
app->argc = argc;
|
||||
#if wxUSE_UNICODE
|
||||
app->argv.Init(argc, argv);
|
||||
#else
|
||||
app->argv = argv;
|
||||
#endif
|
||||
|
||||
wxCallAppCleanup callAppCleanup(app.get());
|
||||
|
||||
|
||||
// common initialization after wxTheApp creation
|
||||
// ---------------------------------------------
|
||||
|
||||
if ( !DoCommonPostInit() )
|
||||
return false;
|
||||
|
||||
|
||||
// prevent the smart pointer from destroying its contents
|
||||
app.release();
|
||||
|
||||
// and the cleanup object from doing cleanup
|
||||
callAppCleanup.Dismiss();
|
||||
|
||||
#if wxUSE_LOG
|
||||
// now that we have a valid wxApp (wxLogGui would have crashed if we used
|
||||
// it before now), we can delete the temporary sink we had created for the
|
||||
// initialization messages -- the next time logging function is called, the
|
||||
// sink will be recreated but this time wxAppTraits will be used
|
||||
delete wxLog::SetActiveTarget(NULL);
|
||||
#endif // wxUSE_LOG
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
|
||||
// we provide a wxEntryStart() wrapper taking "char *" pointer too
|
||||
bool wxEntryStart(int& argc, char **argv)
|
||||
{
|
||||
ConvertArgsToUnicode(argc, argv);
|
||||
|
||||
if ( !wxEntryStart(gs_initData.argc, gs_initData.argv) )
|
||||
{
|
||||
FreeConvertedArgs();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // wxUSE_UNICODE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// clean up
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// cleanup done before destroying wxTheApp
|
||||
static void DoCommonPreCleanup()
|
||||
{
|
||||
#if wxUSE_LOG
|
||||
// flush the logged messages if any and don't use the current probably
|
||||
// unsafe log target any more: the default one (wxLogGui) can't be used
|
||||
// after the resources are freed which happens when we return and the user
|
||||
// supplied one might be even more unsafe (using any wxWidgets GUI function
|
||||
// is unsafe starting from now)
|
||||
//
|
||||
// notice that wxLog will still recreate a default log target if any
|
||||
// messages are logged but that one will be safe to use until the very end
|
||||
delete wxLog::SetActiveTarget(NULL);
|
||||
#endif // wxUSE_LOG
|
||||
}
|
||||
|
||||
// cleanup done after destroying wxTheApp
|
||||
static void DoCommonPostCleanup()
|
||||
{
|
||||
wxModule::CleanUpModules();
|
||||
|
||||
// we can't do this in wxApp itself because it doesn't know if argv had
|
||||
// been allocated
|
||||
#if wxUSE_UNICODE
|
||||
FreeConvertedArgs();
|
||||
#endif // wxUSE_UNICODE
|
||||
|
||||
// use Set(NULL) and not Get() to avoid creating a message output object on
|
||||
// demand when we just want to delete it
|
||||
delete wxMessageOutput::Set(NULL);
|
||||
|
||||
#if wxUSE_LOG
|
||||
// call this first as it has a side effect: in addition to flushing all
|
||||
// logs for this thread, it also flushes everything logged from other
|
||||
// threads
|
||||
wxLog::FlushActive();
|
||||
|
||||
// and now delete the last logger as well
|
||||
//
|
||||
// we still don't disable log target auto-vivification even if any log
|
||||
// objects created now will result in memory leaks because it seems better
|
||||
// to leak memory which doesn't matter much considering the application is
|
||||
// exiting anyhow than to not show messages which could still be logged
|
||||
// from the user code (e.g. static dtors and such)
|
||||
delete wxLog::SetActiveTarget(NULL);
|
||||
#endif // wxUSE_LOG
|
||||
}
|
||||
|
||||
void wxEntryCleanup()
|
||||
{
|
||||
DoCommonPreCleanup();
|
||||
|
||||
|
||||
// delete the application object
|
||||
if ( wxTheApp )
|
||||
{
|
||||
wxTheApp->CleanUp();
|
||||
|
||||
// reset the global pointer to it to NULL before destroying it as in
|
||||
// some circumstances this can result in executing the code using
|
||||
// wxTheApp and using half-destroyed object is no good
|
||||
wxAppConsole * const app = wxApp::GetInstance();
|
||||
wxApp::SetInstance(NULL);
|
||||
delete app;
|
||||
}
|
||||
|
||||
|
||||
DoCommonPostCleanup();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxEntry
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for MSW the real wxEntry is defined in msw/main.cpp
|
||||
#ifndef __WINDOWS__
|
||||
#define wxEntryReal wxEntry
|
||||
#endif // !__WINDOWS__
|
||||
|
||||
int wxEntryReal(int& argc, wxChar **argv)
|
||||
{
|
||||
// library initialization
|
||||
wxInitializer initializer(argc, argv);
|
||||
|
||||
if ( !initializer.IsOk() )
|
||||
{
|
||||
#if wxUSE_LOG
|
||||
// flush any log messages explaining why we failed
|
||||
delete wxLog::SetActiveTarget(NULL);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
wxTRY
|
||||
{
|
||||
// app initialization
|
||||
if ( !wxTheApp->CallOnInit() )
|
||||
{
|
||||
// don't call OnExit() if OnInit() failed
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ensure that OnExit() is called if OnInit() had succeeded
|
||||
class CallOnExit
|
||||
{
|
||||
public:
|
||||
~CallOnExit() { wxTheApp->OnExit(); }
|
||||
} callOnExit;
|
||||
|
||||
WX_SUPPRESS_UNUSED_WARN(callOnExit);
|
||||
|
||||
// app execution
|
||||
return wxTheApp->OnRun();
|
||||
}
|
||||
wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; )
|
||||
}
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
|
||||
// as with wxEntryStart, we provide an ANSI wrapper
|
||||
int wxEntry(int& argc, char **argv)
|
||||
{
|
||||
ConvertArgsToUnicode(argc, argv);
|
||||
|
||||
return wxEntry(gs_initData.argc, gs_initData.argv);
|
||||
}
|
||||
|
||||
#endif // wxUSE_UNICODE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxInitialize/wxUninitialize
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxInitialize()
|
||||
{
|
||||
int argc = 0;
|
||||
return wxInitialize(argc, (wxChar**)NULL);
|
||||
}
|
||||
|
||||
bool wxInitialize(int& argc, wxChar **argv)
|
||||
{
|
||||
wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
|
||||
|
||||
if ( gs_initData.nInitCount++ )
|
||||
{
|
||||
// already initialized
|
||||
return true;
|
||||
}
|
||||
|
||||
return wxEntryStart(argc, argv);
|
||||
}
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
bool wxInitialize(int& argc, char **argv)
|
||||
{
|
||||
wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
|
||||
|
||||
if ( gs_initData.nInitCount++ )
|
||||
{
|
||||
// already initialized
|
||||
return true;
|
||||
}
|
||||
|
||||
return wxEntryStart(argc, argv);
|
||||
}
|
||||
#endif // wxUSE_UNICODE
|
||||
|
||||
void wxUninitialize()
|
||||
{
|
||||
wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
|
||||
|
||||
if ( --gs_initData.nInitCount == 0 )
|
||||
{
|
||||
wxEntryCleanup();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,127 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/ipcbase.cpp
|
||||
// Purpose: IPC base classes
|
||||
// Author: Julian Smart
|
||||
// Modified by:
|
||||
// Created: 04/01/98
|
||||
// Copyright: (c) Julian Smart
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#endif
|
||||
|
||||
#include "wx/ipcbase.h"
|
||||
|
||||
wxIMPLEMENT_ABSTRACT_CLASS(wxServerBase, wxObject)
|
||||
wxIMPLEMENT_ABSTRACT_CLASS(wxClientBase, wxObject)
|
||||
wxIMPLEMENT_ABSTRACT_CLASS(wxConnectionBase, wxObject)
|
||||
|
||||
wxConnectionBase::wxConnectionBase(void *buffer, size_t bytes)
|
||||
: m_buffer((char *)buffer),
|
||||
m_buffersize(bytes),
|
||||
m_deletebufferwhendone(false),
|
||||
m_connected(true)
|
||||
{
|
||||
if ( buffer == NULL )
|
||||
{ // behave like next constructor
|
||||
m_buffersize = 0;
|
||||
m_deletebufferwhendone = true;
|
||||
}
|
||||
}
|
||||
|
||||
wxConnectionBase::wxConnectionBase()
|
||||
: m_buffer(NULL),
|
||||
m_buffersize(0),
|
||||
m_deletebufferwhendone(true),
|
||||
m_connected(true)
|
||||
{
|
||||
}
|
||||
|
||||
wxConnectionBase::wxConnectionBase(const wxConnectionBase& copy)
|
||||
: wxObject(),
|
||||
m_buffer(copy.m_buffer),
|
||||
m_buffersize(copy.m_buffersize),
|
||||
m_deletebufferwhendone(false),
|
||||
m_connected(copy.m_connected)
|
||||
|
||||
{
|
||||
// copy constructor would require ref-counted pointer to buffer
|
||||
wxFAIL_MSG( wxT("Copy constructor of wxConnectionBase not implemented") );
|
||||
}
|
||||
|
||||
|
||||
wxConnectionBase::~wxConnectionBase()
|
||||
{
|
||||
if ( m_deletebufferwhendone )
|
||||
delete [] m_buffer;
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxString wxConnectionBase::GetTextFromData(const void* data,
|
||||
size_t size,
|
||||
wxIPCFormat fmt)
|
||||
{
|
||||
wxString s;
|
||||
switch ( fmt )
|
||||
{
|
||||
case wxIPC_TEXT:
|
||||
// normally the string should be NUL-terminated and size should
|
||||
// include the total size of the buffer, including NUL -- but don't
|
||||
// crash (by trying to access (size_t)-1 bytes) if it doesn't
|
||||
if ( size )
|
||||
size--;
|
||||
|
||||
s = wxString(static_cast<const char *>(data), size);
|
||||
break;
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
// TODO: we should handle both wxIPC_UTF16TEXT and wxIPC_UTF32TEXT here
|
||||
// for inter-platform IPC
|
||||
case wxIPC_UNICODETEXT:
|
||||
wxASSERT_MSG( !(size % sizeof(wchar_t)), "invalid buffer size" );
|
||||
if ( size )
|
||||
{
|
||||
size /= sizeof(wchar_t);
|
||||
size--;
|
||||
}
|
||||
|
||||
s = wxString(static_cast<const wchar_t *>(data), size);
|
||||
break;
|
||||
|
||||
case wxIPC_UTF8TEXT:
|
||||
if ( size )
|
||||
size--;
|
||||
|
||||
s = wxString::FromUTF8(static_cast<const char *>(data), size);
|
||||
break;
|
||||
#endif // wxUSE_UNICODE
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( "non-string IPC format in GetTextFromData()" );
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void *wxConnectionBase::GetBufferAtLeast( size_t bytes )
|
||||
{
|
||||
if ( m_buffersize >= bytes )
|
||||
return m_buffer;
|
||||
else
|
||||
{ // need to resize buffer
|
||||
if ( m_deletebufferwhendone )
|
||||
{ // we're in charge of buffer, increase it
|
||||
delete [] m_buffer;
|
||||
m_buffer = new char[bytes];
|
||||
m_buffersize = bytes;
|
||||
return m_buffer;
|
||||
} // user-supplied buffer, fail
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,799 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/languageinfo.cpp
|
||||
// Purpose: wxLocale::InitLanguagesDB()
|
||||
// Author: Vadim Zeitlin, Vaclav Slavik
|
||||
// Created: 2010-04-23
|
||||
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declaration
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/intl.h"
|
||||
|
||||
#if wxUSE_INTL
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include "wx/msw/private.h"
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// default languages table & initialization
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// --- --- --- generated code begins here --- --- ---
|
||||
|
||||
// This table is generated by misc/languages/genlang.py
|
||||
// When making changes, please put them into misc/languages/langtabl.txt
|
||||
|
||||
#if !defined(__WIN32__)
|
||||
|
||||
#define SETWINLANG(info,lang,sublang)
|
||||
|
||||
#else
|
||||
|
||||
#define SETWINLANG(info,lang,sublang) \
|
||||
info.WinLang = lang, info.WinSublang = sublang;
|
||||
|
||||
#ifndef LANG_AFRIKAANS
|
||||
#define LANG_AFRIKAANS (0)
|
||||
#endif
|
||||
#ifndef LANG_ALBANIAN
|
||||
#define LANG_ALBANIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_ARABIC
|
||||
#define LANG_ARABIC (0)
|
||||
#endif
|
||||
#ifndef LANG_ARMENIAN
|
||||
#define LANG_ARMENIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_ASSAMESE
|
||||
#define LANG_ASSAMESE (0)
|
||||
#endif
|
||||
#ifndef LANG_AZERI
|
||||
#define LANG_AZERI (0)
|
||||
#endif
|
||||
#ifndef LANG_BASQUE
|
||||
#define LANG_BASQUE (0)
|
||||
#endif
|
||||
#ifndef LANG_BELARUSIAN
|
||||
#define LANG_BELARUSIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_BENGALI
|
||||
#define LANG_BENGALI (0)
|
||||
#endif
|
||||
#ifndef LANG_BOSNIAN
|
||||
#define LANG_BOSNIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_BULGARIAN
|
||||
#define LANG_BULGARIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_CATALAN
|
||||
#define LANG_CATALAN (0)
|
||||
#endif
|
||||
#ifndef LANG_CHINESE
|
||||
#define LANG_CHINESE (0)
|
||||
#endif
|
||||
#ifndef LANG_CROATIAN
|
||||
#define LANG_CROATIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_CZECH
|
||||
#define LANG_CZECH (0)
|
||||
#endif
|
||||
#ifndef LANG_DANISH
|
||||
#define LANG_DANISH (0)
|
||||
#endif
|
||||
#ifndef LANG_DUTCH
|
||||
#define LANG_DUTCH (0)
|
||||
#endif
|
||||
#ifndef LANG_ENGLISH
|
||||
#define LANG_ENGLISH (0)
|
||||
#endif
|
||||
#ifndef LANG_ESTONIAN
|
||||
#define LANG_ESTONIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_FAEROESE
|
||||
#define LANG_FAEROESE (0)
|
||||
#endif
|
||||
#ifndef LANG_FARSI
|
||||
#define LANG_FARSI (0)
|
||||
#endif
|
||||
#ifndef LANG_FINNISH
|
||||
#define LANG_FINNISH (0)
|
||||
#endif
|
||||
#ifndef LANG_FRENCH
|
||||
#define LANG_FRENCH (0)
|
||||
#endif
|
||||
#ifndef LANG_FRISIAN
|
||||
#define LANG_FRISIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_GEORGIAN
|
||||
#define LANG_GEORGIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_GERMAN
|
||||
#define LANG_GERMAN (0)
|
||||
#endif
|
||||
#ifndef LANG_GREEK
|
||||
#define LANG_GREEK (0)
|
||||
#endif
|
||||
#ifndef LANG_GUJARATI
|
||||
#define LANG_GUJARATI (0)
|
||||
#endif
|
||||
#ifndef LANG_HEBREW
|
||||
#define LANG_HEBREW (0)
|
||||
#endif
|
||||
#ifndef LANG_HINDI
|
||||
#define LANG_HINDI (0)
|
||||
#endif
|
||||
#ifndef LANG_HUNGARIAN
|
||||
#define LANG_HUNGARIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_ICELANDIC
|
||||
#define LANG_ICELANDIC (0)
|
||||
#endif
|
||||
#ifndef LANG_INDONESIAN
|
||||
#define LANG_INDONESIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_ITALIAN
|
||||
#define LANG_ITALIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_JAPANESE
|
||||
#define LANG_JAPANESE (0)
|
||||
#endif
|
||||
#ifndef LANG_KABYLE
|
||||
#define LANG_KABYLE (0)
|
||||
#endif
|
||||
#ifndef LANG_KANNADA
|
||||
#define LANG_KANNADA (0)
|
||||
#endif
|
||||
#ifndef LANG_KASHMIRI
|
||||
#define LANG_KASHMIRI (0)
|
||||
#endif
|
||||
#ifndef LANG_KAZAK
|
||||
#define LANG_KAZAK (0)
|
||||
#endif
|
||||
#ifndef LANG_KONKANI
|
||||
#define LANG_KONKANI (0)
|
||||
#endif
|
||||
#ifndef LANG_KOREAN
|
||||
#define LANG_KOREAN (0)
|
||||
#endif
|
||||
#ifndef LANG_LATVIAN
|
||||
#define LANG_LATVIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_LITHUANIAN
|
||||
#define LANG_LITHUANIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_MACEDONIAN
|
||||
#define LANG_MACEDONIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_MALAY
|
||||
#define LANG_MALAY (0)
|
||||
#endif
|
||||
#ifndef LANG_MALAYALAM
|
||||
#define LANG_MALAYALAM (0)
|
||||
#endif
|
||||
#ifndef LANG_MANIPURI
|
||||
#define LANG_MANIPURI (0)
|
||||
#endif
|
||||
#ifndef LANG_MARATHI
|
||||
#define LANG_MARATHI (0)
|
||||
#endif
|
||||
#ifndef LANG_NEPALI
|
||||
#define LANG_NEPALI (0)
|
||||
#endif
|
||||
#ifndef LANG_NORWEGIAN
|
||||
#define LANG_NORWEGIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_ORIYA
|
||||
#define LANG_ORIYA (0)
|
||||
#endif
|
||||
#ifndef LANG_POLISH
|
||||
#define LANG_POLISH (0)
|
||||
#endif
|
||||
#ifndef LANG_PORTUGUESE
|
||||
#define LANG_PORTUGUESE (0)
|
||||
#endif
|
||||
#ifndef LANG_PUNJABI
|
||||
#define LANG_PUNJABI (0)
|
||||
#endif
|
||||
#ifndef LANG_ROMANIAN
|
||||
#define LANG_ROMANIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_RUSSIAN
|
||||
#define LANG_RUSSIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_SAMI
|
||||
#define LANG_SAMI (0)
|
||||
#endif
|
||||
#ifndef LANG_SANSKRIT
|
||||
#define LANG_SANSKRIT (0)
|
||||
#endif
|
||||
#ifndef LANG_SERBIAN
|
||||
#define LANG_SERBIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_SINDHI
|
||||
#define LANG_SINDHI (0)
|
||||
#endif
|
||||
#ifndef LANG_SLOVAK
|
||||
#define LANG_SLOVAK (0)
|
||||
#endif
|
||||
#ifndef LANG_SLOVENIAN
|
||||
#define LANG_SLOVENIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_SPANISH
|
||||
#define LANG_SPANISH (0)
|
||||
#endif
|
||||
#ifndef LANG_SWAHILI
|
||||
#define LANG_SWAHILI (0)
|
||||
#endif
|
||||
#ifndef LANG_SWEDISH
|
||||
#define LANG_SWEDISH (0)
|
||||
#endif
|
||||
#ifndef LANG_TAMIL
|
||||
#define LANG_TAMIL (0)
|
||||
#endif
|
||||
#ifndef LANG_TATAR
|
||||
#define LANG_TATAR (0)
|
||||
#endif
|
||||
#ifndef LANG_TELUGU
|
||||
#define LANG_TELUGU (0)
|
||||
#endif
|
||||
#ifndef LANG_THAI
|
||||
#define LANG_THAI (0)
|
||||
#endif
|
||||
#ifndef LANG_TURKISH
|
||||
#define LANG_TURKISH (0)
|
||||
#endif
|
||||
#ifndef LANG_UKRAINIAN
|
||||
#define LANG_UKRAINIAN (0)
|
||||
#endif
|
||||
#ifndef LANG_URDU
|
||||
#define LANG_URDU (0)
|
||||
#endif
|
||||
#ifndef LANG_UZBEK
|
||||
#define LANG_UZBEK (0)
|
||||
#endif
|
||||
#ifndef LANG_VIETNAMESE
|
||||
#define LANG_VIETNAMESE (0)
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_ALGERIA
|
||||
#define SUBLANG_ARABIC_ALGERIA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_BAHRAIN
|
||||
#define SUBLANG_ARABIC_BAHRAIN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_EGYPT
|
||||
#define SUBLANG_ARABIC_EGYPT SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_IRAQ
|
||||
#define SUBLANG_ARABIC_IRAQ SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_JORDAN
|
||||
#define SUBLANG_ARABIC_JORDAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_KUWAIT
|
||||
#define SUBLANG_ARABIC_KUWAIT SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_LEBANON
|
||||
#define SUBLANG_ARABIC_LEBANON SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_LIBYA
|
||||
#define SUBLANG_ARABIC_LIBYA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_MOROCCO
|
||||
#define SUBLANG_ARABIC_MOROCCO SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_OMAN
|
||||
#define SUBLANG_ARABIC_OMAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_QATAR
|
||||
#define SUBLANG_ARABIC_QATAR SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_SAUDI_ARABIA
|
||||
#define SUBLANG_ARABIC_SAUDI_ARABIA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_SYRIA
|
||||
#define SUBLANG_ARABIC_SYRIA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_TUNISIA
|
||||
#define SUBLANG_ARABIC_TUNISIA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_UAE
|
||||
#define SUBLANG_ARABIC_UAE SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ARABIC_YEMEN
|
||||
#define SUBLANG_ARABIC_YEMEN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_AZERI_CYRILLIC
|
||||
#define SUBLANG_AZERI_CYRILLIC SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_AZERI_LATIN
|
||||
#define SUBLANG_AZERI_LATIN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN
|
||||
#define SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_CHINESE_SIMPLIFIED
|
||||
#define SUBLANG_CHINESE_SIMPLIFIED SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_CHINESE_TRADITIONAL
|
||||
#define SUBLANG_CHINESE_TRADITIONAL SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_CHINESE_HONGKONG
|
||||
#define SUBLANG_CHINESE_HONGKONG SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_CHINESE_MACAU
|
||||
#define SUBLANG_CHINESE_MACAU SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_CHINESE_SINGAPORE
|
||||
#define SUBLANG_CHINESE_SINGAPORE SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_DUTCH
|
||||
#define SUBLANG_DUTCH SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_DUTCH_BELGIAN
|
||||
#define SUBLANG_DUTCH_BELGIAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_UK
|
||||
#define SUBLANG_ENGLISH_UK SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_US
|
||||
#define SUBLANG_ENGLISH_US SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_AUS
|
||||
#define SUBLANG_ENGLISH_AUS SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_BELIZE
|
||||
#define SUBLANG_ENGLISH_BELIZE SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_CAN
|
||||
#define SUBLANG_ENGLISH_CAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_CARIBBEAN
|
||||
#define SUBLANG_ENGLISH_CARIBBEAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_EIRE
|
||||
#define SUBLANG_ENGLISH_EIRE SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_JAMAICA
|
||||
#define SUBLANG_ENGLISH_JAMAICA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_NZ
|
||||
#define SUBLANG_ENGLISH_NZ SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_PHILIPPINES
|
||||
#define SUBLANG_ENGLISH_PHILIPPINES SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_SOUTH_AFRICA
|
||||
#define SUBLANG_ENGLISH_SOUTH_AFRICA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_TRINIDAD
|
||||
#define SUBLANG_ENGLISH_TRINIDAD SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ENGLISH_ZIMBABWE
|
||||
#define SUBLANG_ENGLISH_ZIMBABWE SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_FRENCH
|
||||
#define SUBLANG_FRENCH SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_FRENCH_BELGIAN
|
||||
#define SUBLANG_FRENCH_BELGIAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_FRENCH_CANADIAN
|
||||
#define SUBLANG_FRENCH_CANADIAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_FRENCH_LUXEMBOURG
|
||||
#define SUBLANG_FRENCH_LUXEMBOURG SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_FRENCH_MONACO
|
||||
#define SUBLANG_FRENCH_MONACO SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_FRENCH_SWISS
|
||||
#define SUBLANG_FRENCH_SWISS SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_GERMAN
|
||||
#define SUBLANG_GERMAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_GERMAN_AUSTRIAN
|
||||
#define SUBLANG_GERMAN_AUSTRIAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_GERMAN_LIECHTENSTEIN
|
||||
#define SUBLANG_GERMAN_LIECHTENSTEIN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_GERMAN_LUXEMBOURG
|
||||
#define SUBLANG_GERMAN_LUXEMBOURG SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_GERMAN_SWISS
|
||||
#define SUBLANG_GERMAN_SWISS SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ITALIAN
|
||||
#define SUBLANG_ITALIAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_ITALIAN_SWISS
|
||||
#define SUBLANG_ITALIAN_SWISS SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_KASHMIRI_INDIA
|
||||
#define SUBLANG_KASHMIRI_INDIA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_KOREAN
|
||||
#define SUBLANG_KOREAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_LITHUANIAN
|
||||
#define SUBLANG_LITHUANIAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
|
||||
#define SUBLANG_MALAY_BRUNEI_DARUSSALAM SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_MALAY_MALAYSIA
|
||||
#define SUBLANG_MALAY_MALAYSIA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_NEPALI_INDIA
|
||||
#define SUBLANG_NEPALI_INDIA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_NORWEGIAN_BOKMAL
|
||||
#define SUBLANG_NORWEGIAN_BOKMAL SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_NORWEGIAN_NYNORSK
|
||||
#define SUBLANG_NORWEGIAN_NYNORSK SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_PORTUGUESE
|
||||
#define SUBLANG_PORTUGUESE SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_PORTUGUESE_BRAZILIAN
|
||||
#define SUBLANG_PORTUGUESE_BRAZILIAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SERBIAN_CYRILLIC
|
||||
#define SUBLANG_SERBIAN_CYRILLIC SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SERBIAN_LATIN
|
||||
#define SUBLANG_SERBIAN_LATIN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH
|
||||
#define SUBLANG_SPANISH SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_ARGENTINA
|
||||
#define SUBLANG_SPANISH_ARGENTINA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_BOLIVIA
|
||||
#define SUBLANG_SPANISH_BOLIVIA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_CHILE
|
||||
#define SUBLANG_SPANISH_CHILE SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_COLOMBIA
|
||||
#define SUBLANG_SPANISH_COLOMBIA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_COSTA_RICA
|
||||
#define SUBLANG_SPANISH_COSTA_RICA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC
|
||||
#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_ECUADOR
|
||||
#define SUBLANG_SPANISH_ECUADOR SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_EL_SALVADOR
|
||||
#define SUBLANG_SPANISH_EL_SALVADOR SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_GUATEMALA
|
||||
#define SUBLANG_SPANISH_GUATEMALA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_HONDURAS
|
||||
#define SUBLANG_SPANISH_HONDURAS SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_MEXICAN
|
||||
#define SUBLANG_SPANISH_MEXICAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_MODERN
|
||||
#define SUBLANG_SPANISH_MODERN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_NICARAGUA
|
||||
#define SUBLANG_SPANISH_NICARAGUA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_PANAMA
|
||||
#define SUBLANG_SPANISH_PANAMA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_PARAGUAY
|
||||
#define SUBLANG_SPANISH_PARAGUAY SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_PERU
|
||||
#define SUBLANG_SPANISH_PERU SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_PUERTO_RICO
|
||||
#define SUBLANG_SPANISH_PUERTO_RICO SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_URUGUAY
|
||||
#define SUBLANG_SPANISH_URUGUAY SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SPANISH_VENEZUELA
|
||||
#define SUBLANG_SPANISH_VENEZUELA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SWEDISH
|
||||
#define SUBLANG_SWEDISH SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_SWEDISH_FINLAND
|
||||
#define SUBLANG_SWEDISH_FINLAND SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_URDU_INDIA
|
||||
#define SUBLANG_URDU_INDIA SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_URDU_PAKISTAN
|
||||
#define SUBLANG_URDU_PAKISTAN SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_UZBEK_CYRILLIC
|
||||
#define SUBLANG_UZBEK_CYRILLIC SUBLANG_DEFAULT
|
||||
#endif
|
||||
#ifndef SUBLANG_UZBEK_LATIN
|
||||
#define SUBLANG_UZBEK_LATIN SUBLANG_DEFAULT
|
||||
#endif
|
||||
|
||||
|
||||
#endif // __WIN32__
|
||||
|
||||
#define LNG(wxlang, canonical, winlang, winsublang, layout, desc) \
|
||||
info.Language = wxlang; \
|
||||
info.CanonicalName = wxT(canonical); \
|
||||
info.LayoutDirection = layout; \
|
||||
info.Description = wxT(desc); \
|
||||
SETWINLANG(info, winlang, winsublang) \
|
||||
AddLanguage(info);
|
||||
|
||||
void wxLocale::InitLanguagesDB()
|
||||
{
|
||||
wxLanguageInfo info;
|
||||
|
||||
LNG(wxLANGUAGE_ABKHAZIAN, "ab" , 0 , 0 , wxLayout_LeftToRight, "Abkhazian")
|
||||
LNG(wxLANGUAGE_AFAR, "aa" , 0 , 0 , wxLayout_LeftToRight, "Afar")
|
||||
LNG(wxLANGUAGE_AFRIKAANS, "af_ZA", LANG_AFRIKAANS , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Afrikaans")
|
||||
LNG(wxLANGUAGE_ALBANIAN, "sq_AL", LANG_ALBANIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Albanian")
|
||||
LNG(wxLANGUAGE_AMHARIC, "am" , 0 , 0 , wxLayout_LeftToRight, "Amharic")
|
||||
LNG(wxLANGUAGE_ARABIC, "ar" , LANG_ARABIC , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Arabic")
|
||||
LNG(wxLANGUAGE_ARABIC_ALGERIA, "ar_DZ", LANG_ARABIC , SUBLANG_ARABIC_ALGERIA , wxLayout_RightToLeft, "Arabic (Algeria)")
|
||||
LNG(wxLANGUAGE_ARABIC_BAHRAIN, "ar_BH", LANG_ARABIC , SUBLANG_ARABIC_BAHRAIN , wxLayout_RightToLeft, "Arabic (Bahrain)")
|
||||
LNG(wxLANGUAGE_ARABIC_EGYPT, "ar_EG", LANG_ARABIC , SUBLANG_ARABIC_EGYPT , wxLayout_RightToLeft, "Arabic (Egypt)")
|
||||
LNG(wxLANGUAGE_ARABIC_IRAQ, "ar_IQ", LANG_ARABIC , SUBLANG_ARABIC_IRAQ , wxLayout_RightToLeft, "Arabic (Iraq)")
|
||||
LNG(wxLANGUAGE_ARABIC_JORDAN, "ar_JO", LANG_ARABIC , SUBLANG_ARABIC_JORDAN , wxLayout_RightToLeft, "Arabic (Jordan)")
|
||||
LNG(wxLANGUAGE_ARABIC_KUWAIT, "ar_KW", LANG_ARABIC , SUBLANG_ARABIC_KUWAIT , wxLayout_RightToLeft, "Arabic (Kuwait)")
|
||||
LNG(wxLANGUAGE_ARABIC_LEBANON, "ar_LB", LANG_ARABIC , SUBLANG_ARABIC_LEBANON , wxLayout_RightToLeft, "Arabic (Lebanon)")
|
||||
LNG(wxLANGUAGE_ARABIC_LIBYA, "ar_LY", LANG_ARABIC , SUBLANG_ARABIC_LIBYA , wxLayout_RightToLeft, "Arabic (Libya)")
|
||||
LNG(wxLANGUAGE_ARABIC_MOROCCO, "ar_MA", LANG_ARABIC , SUBLANG_ARABIC_MOROCCO , wxLayout_RightToLeft, "Arabic (Morocco)")
|
||||
LNG(wxLANGUAGE_ARABIC_OMAN, "ar_OM", LANG_ARABIC , SUBLANG_ARABIC_OMAN , wxLayout_RightToLeft, "Arabic (Oman)")
|
||||
LNG(wxLANGUAGE_ARABIC_QATAR, "ar_QA", LANG_ARABIC , SUBLANG_ARABIC_QATAR , wxLayout_RightToLeft, "Arabic (Qatar)")
|
||||
LNG(wxLANGUAGE_ARABIC_SAUDI_ARABIA, "ar_SA", LANG_ARABIC , SUBLANG_ARABIC_SAUDI_ARABIA , wxLayout_RightToLeft, "Arabic (Saudi Arabia)")
|
||||
LNG(wxLANGUAGE_ARABIC_SUDAN, "ar_SD", 0 , 0 , wxLayout_RightToLeft, "Arabic (Sudan)")
|
||||
LNG(wxLANGUAGE_ARABIC_SYRIA, "ar_SY", LANG_ARABIC , SUBLANG_ARABIC_SYRIA , wxLayout_RightToLeft, "Arabic (Syria)")
|
||||
LNG(wxLANGUAGE_ARABIC_TUNISIA, "ar_TN", LANG_ARABIC , SUBLANG_ARABIC_TUNISIA , wxLayout_RightToLeft, "Arabic (Tunisia)")
|
||||
LNG(wxLANGUAGE_ARABIC_UAE, "ar_AE", LANG_ARABIC , SUBLANG_ARABIC_UAE , wxLayout_RightToLeft, "Arabic (Uae)")
|
||||
LNG(wxLANGUAGE_ARABIC_YEMEN, "ar_YE", LANG_ARABIC , SUBLANG_ARABIC_YEMEN , wxLayout_RightToLeft, "Arabic (Yemen)")
|
||||
LNG(wxLANGUAGE_ARMENIAN, "hy" , LANG_ARMENIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Armenian")
|
||||
LNG(wxLANGUAGE_ASSAMESE, "as" , LANG_ASSAMESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Assamese")
|
||||
LNG(wxLANGUAGE_ASTURIAN, "ast" , 0 , 0 , wxLayout_LeftToRight, "Asturian")
|
||||
LNG(wxLANGUAGE_AYMARA, "ay" , 0 , 0 , wxLayout_LeftToRight, "Aymara")
|
||||
LNG(wxLANGUAGE_AZERI, "az" , LANG_AZERI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Azeri")
|
||||
LNG(wxLANGUAGE_AZERI_CYRILLIC, "az" , LANG_AZERI , SUBLANG_AZERI_CYRILLIC , wxLayout_LeftToRight, "Azeri (Cyrillic)")
|
||||
LNG(wxLANGUAGE_AZERI_LATIN, "az" , LANG_AZERI , SUBLANG_AZERI_LATIN , wxLayout_LeftToRight, "Azeri (Latin)")
|
||||
LNG(wxLANGUAGE_BASHKIR, "ba" , 0 , 0 , wxLayout_LeftToRight, "Bashkir")
|
||||
LNG(wxLANGUAGE_BASQUE, "eu_ES", LANG_BASQUE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Basque")
|
||||
LNG(wxLANGUAGE_BELARUSIAN, "be_BY", LANG_BELARUSIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Belarusian")
|
||||
LNG(wxLANGUAGE_BENGALI, "bn" , LANG_BENGALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Bengali")
|
||||
LNG(wxLANGUAGE_BHUTANI, "dz" , 0 , 0 , wxLayout_LeftToRight, "Bhutani")
|
||||
LNG(wxLANGUAGE_BIHARI, "bh" , 0 , 0 , wxLayout_LeftToRight, "Bihari")
|
||||
LNG(wxLANGUAGE_BISLAMA, "bi" , 0 , 0 , wxLayout_LeftToRight, "Bislama")
|
||||
LNG(wxLANGUAGE_BOSNIAN, "bs" , LANG_BOSNIAN , SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN, wxLayout_LeftToRight, "Bosnian")
|
||||
LNG(wxLANGUAGE_BRETON, "br" , 0 , 0 , wxLayout_LeftToRight, "Breton")
|
||||
LNG(wxLANGUAGE_BULGARIAN, "bg_BG", LANG_BULGARIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Bulgarian")
|
||||
LNG(wxLANGUAGE_BURMESE, "my" , 0 , 0 , wxLayout_LeftToRight, "Burmese")
|
||||
LNG(wxLANGUAGE_CATALAN, "ca_ES", LANG_CATALAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Catalan")
|
||||
LNG(wxLANGUAGE_CHINESE, "zh_TW", LANG_CHINESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Chinese")
|
||||
LNG(wxLANGUAGE_CHINESE_SIMPLIFIED, "zh_CN", LANG_CHINESE , SUBLANG_CHINESE_SIMPLIFIED , wxLayout_LeftToRight, "Chinese (Simplified)")
|
||||
LNG(wxLANGUAGE_CHINESE_TRADITIONAL, "zh_TW", LANG_CHINESE , SUBLANG_CHINESE_TRADITIONAL , wxLayout_LeftToRight, "Chinese (Traditional)")
|
||||
LNG(wxLANGUAGE_CHINESE_HONGKONG, "zh_HK", LANG_CHINESE , SUBLANG_CHINESE_HONGKONG , wxLayout_LeftToRight, "Chinese (Hongkong)")
|
||||
LNG(wxLANGUAGE_CHINESE_MACAU, "zh_MO", LANG_CHINESE , SUBLANG_CHINESE_MACAU , wxLayout_LeftToRight, "Chinese (Macau)")
|
||||
LNG(wxLANGUAGE_CHINESE_SINGAPORE, "zh_SG", LANG_CHINESE , SUBLANG_CHINESE_SINGAPORE , wxLayout_LeftToRight, "Chinese (Singapore)")
|
||||
LNG(wxLANGUAGE_CHINESE_TAIWAN, "zh_TW", LANG_CHINESE , SUBLANG_CHINESE_TRADITIONAL , wxLayout_LeftToRight, "Chinese (Taiwan)")
|
||||
LNG(wxLANGUAGE_CORSICAN, "co" , 0 , 0 , wxLayout_LeftToRight, "Corsican")
|
||||
LNG(wxLANGUAGE_CROATIAN, "hr_HR", LANG_CROATIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Croatian")
|
||||
LNG(wxLANGUAGE_CZECH, "cs_CZ", LANG_CZECH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Czech")
|
||||
LNG(wxLANGUAGE_DANISH, "da_DK", LANG_DANISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Danish")
|
||||
LNG(wxLANGUAGE_DUTCH, "nl_NL", LANG_DUTCH , SUBLANG_DUTCH , wxLayout_LeftToRight, "Dutch")
|
||||
LNG(wxLANGUAGE_DUTCH_BELGIAN, "nl_BE", LANG_DUTCH , SUBLANG_DUTCH_BELGIAN , wxLayout_LeftToRight, "Dutch (Belgian)")
|
||||
LNG(wxLANGUAGE_ENGLISH, "en_GB", LANG_ENGLISH , SUBLANG_ENGLISH_UK , wxLayout_LeftToRight, "English")
|
||||
LNG(wxLANGUAGE_ENGLISH_UK, "en_GB", LANG_ENGLISH , SUBLANG_ENGLISH_UK , wxLayout_LeftToRight, "English (U.K.)")
|
||||
LNG(wxLANGUAGE_ENGLISH_US, "en_US", LANG_ENGLISH , SUBLANG_ENGLISH_US , wxLayout_LeftToRight, "English (U.S.)")
|
||||
LNG(wxLANGUAGE_ENGLISH_AUSTRALIA, "en_AU", LANG_ENGLISH , SUBLANG_ENGLISH_AUS , wxLayout_LeftToRight, "English (Australia)")
|
||||
LNG(wxLANGUAGE_ENGLISH_BELIZE, "en_BZ", LANG_ENGLISH , SUBLANG_ENGLISH_BELIZE , wxLayout_LeftToRight, "English (Belize)")
|
||||
LNG(wxLANGUAGE_ENGLISH_BOTSWANA, "en_BW", 0 , 0 , wxLayout_LeftToRight, "English (Botswana)")
|
||||
LNG(wxLANGUAGE_ENGLISH_CANADA, "en_CA", LANG_ENGLISH , SUBLANG_ENGLISH_CAN , wxLayout_LeftToRight, "English (Canada)")
|
||||
LNG(wxLANGUAGE_ENGLISH_CARIBBEAN, "en_CB", LANG_ENGLISH , SUBLANG_ENGLISH_CARIBBEAN , wxLayout_LeftToRight, "English (Caribbean)")
|
||||
LNG(wxLANGUAGE_ENGLISH_DENMARK, "en_DK", 0 , 0 , wxLayout_LeftToRight, "English (Denmark)")
|
||||
LNG(wxLANGUAGE_ENGLISH_EIRE, "en_IE", LANG_ENGLISH , SUBLANG_ENGLISH_EIRE , wxLayout_LeftToRight, "English (Eire)")
|
||||
LNG(wxLANGUAGE_ENGLISH_ISRAEL, "en_IL", 0 , 0 , wxLayout_LeftToRight, "English (Israel)")
|
||||
LNG(wxLANGUAGE_ENGLISH_JAMAICA, "en_JM", LANG_ENGLISH , SUBLANG_ENGLISH_JAMAICA , wxLayout_LeftToRight, "English (Jamaica)")
|
||||
LNG(wxLANGUAGE_ENGLISH_NEW_ZEALAND, "en_NZ", LANG_ENGLISH , SUBLANG_ENGLISH_NZ , wxLayout_LeftToRight, "English (New Zealand)")
|
||||
LNG(wxLANGUAGE_ENGLISH_PHILIPPINES, "en_PH", LANG_ENGLISH , SUBLANG_ENGLISH_PHILIPPINES , wxLayout_LeftToRight, "English (Philippines)")
|
||||
LNG(wxLANGUAGE_ENGLISH_SOUTH_AFRICA, "en_ZA", LANG_ENGLISH , SUBLANG_ENGLISH_SOUTH_AFRICA , wxLayout_LeftToRight, "English (South Africa)")
|
||||
LNG(wxLANGUAGE_ENGLISH_TRINIDAD, "en_TT", LANG_ENGLISH , SUBLANG_ENGLISH_TRINIDAD , wxLayout_LeftToRight, "English (Trinidad)")
|
||||
LNG(wxLANGUAGE_ENGLISH_ZIMBABWE, "en_ZW", LANG_ENGLISH , SUBLANG_ENGLISH_ZIMBABWE , wxLayout_LeftToRight, "English (Zimbabwe)")
|
||||
LNG(wxLANGUAGE_ESPERANTO, "eo" , 0 , 0 , wxLayout_LeftToRight, "Esperanto")
|
||||
LNG(wxLANGUAGE_ESTONIAN, "et_EE", LANG_ESTONIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Estonian")
|
||||
LNG(wxLANGUAGE_FAEROESE, "fo_FO", LANG_FAEROESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Faeroese")
|
||||
LNG(wxLANGUAGE_FARSI, "fa_IR", LANG_FARSI , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Farsi")
|
||||
LNG(wxLANGUAGE_FIJI, "fj" , 0 , 0 , wxLayout_LeftToRight, "Fiji")
|
||||
LNG(wxLANGUAGE_FINNISH, "fi_FI", LANG_FINNISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Finnish")
|
||||
LNG(wxLANGUAGE_FRENCH, "fr_FR", LANG_FRENCH , SUBLANG_FRENCH , wxLayout_LeftToRight, "French")
|
||||
LNG(wxLANGUAGE_FRENCH_BELGIAN, "fr_BE", LANG_FRENCH , SUBLANG_FRENCH_BELGIAN , wxLayout_LeftToRight, "French (Belgian)")
|
||||
LNG(wxLANGUAGE_FRENCH_CANADIAN, "fr_CA", LANG_FRENCH , SUBLANG_FRENCH_CANADIAN , wxLayout_LeftToRight, "French (Canadian)")
|
||||
LNG(wxLANGUAGE_FRENCH_LUXEMBOURG, "fr_LU", LANG_FRENCH , SUBLANG_FRENCH_LUXEMBOURG , wxLayout_LeftToRight, "French (Luxembourg)")
|
||||
LNG(wxLANGUAGE_FRENCH_MONACO, "fr_MC", LANG_FRENCH , SUBLANG_FRENCH_MONACO , wxLayout_LeftToRight, "French (Monaco)")
|
||||
LNG(wxLANGUAGE_FRENCH_SWISS, "fr_CH", LANG_FRENCH , SUBLANG_FRENCH_SWISS , wxLayout_LeftToRight, "French (Swiss)")
|
||||
LNG(wxLANGUAGE_FRISIAN, "fy" , LANG_FRISIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Frisian")
|
||||
LNG(wxLANGUAGE_GALICIAN, "gl_ES", 0 , 0 , wxLayout_LeftToRight, "Galician")
|
||||
LNG(wxLANGUAGE_GEORGIAN, "ka_GE", LANG_GEORGIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Georgian")
|
||||
LNG(wxLANGUAGE_GERMAN, "de_DE", LANG_GERMAN , SUBLANG_GERMAN , wxLayout_LeftToRight, "German")
|
||||
LNG(wxLANGUAGE_GERMAN_AUSTRIAN, "de_AT", LANG_GERMAN , SUBLANG_GERMAN_AUSTRIAN , wxLayout_LeftToRight, "German (Austrian)")
|
||||
LNG(wxLANGUAGE_GERMAN_BELGIUM, "de_BE", 0 , 0 , wxLayout_LeftToRight, "German (Belgium)")
|
||||
LNG(wxLANGUAGE_GERMAN_LIECHTENSTEIN, "de_LI", LANG_GERMAN , SUBLANG_GERMAN_LIECHTENSTEIN , wxLayout_LeftToRight, "German (Liechtenstein)")
|
||||
LNG(wxLANGUAGE_GERMAN_LUXEMBOURG, "de_LU", LANG_GERMAN , SUBLANG_GERMAN_LUXEMBOURG , wxLayout_LeftToRight, "German (Luxembourg)")
|
||||
LNG(wxLANGUAGE_GERMAN_SWISS, "de_CH", LANG_GERMAN , SUBLANG_GERMAN_SWISS , wxLayout_LeftToRight, "German (Swiss)")
|
||||
LNG(wxLANGUAGE_GREEK, "el_GR", LANG_GREEK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Greek")
|
||||
LNG(wxLANGUAGE_GREENLANDIC, "kl_GL", 0 , 0 , wxLayout_LeftToRight, "Greenlandic")
|
||||
LNG(wxLANGUAGE_GUARANI, "gn" , 0 , 0 , wxLayout_LeftToRight, "Guarani")
|
||||
LNG(wxLANGUAGE_GUJARATI, "gu" , LANG_GUJARATI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Gujarati")
|
||||
LNG(wxLANGUAGE_HAUSA, "ha" , 0 , 0 , wxLayout_LeftToRight, "Hausa")
|
||||
LNG(wxLANGUAGE_HEBREW, "he_IL", LANG_HEBREW , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Hebrew")
|
||||
LNG(wxLANGUAGE_HINDI, "hi_IN", LANG_HINDI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Hindi")
|
||||
LNG(wxLANGUAGE_HUNGARIAN, "hu_HU", LANG_HUNGARIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Hungarian")
|
||||
LNG(wxLANGUAGE_ICELANDIC, "is_IS", LANG_ICELANDIC , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Icelandic")
|
||||
LNG(wxLANGUAGE_INDONESIAN, "id_ID", LANG_INDONESIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Indonesian")
|
||||
LNG(wxLANGUAGE_INTERLINGUA, "ia" , 0 , 0 , wxLayout_LeftToRight, "Interlingua")
|
||||
LNG(wxLANGUAGE_INTERLINGUE, "ie" , 0 , 0 , wxLayout_LeftToRight, "Interlingue")
|
||||
LNG(wxLANGUAGE_INUKTITUT, "iu" , 0 , 0 , wxLayout_LeftToRight, "Inuktitut")
|
||||
LNG(wxLANGUAGE_INUPIAK, "ik" , 0 , 0 , wxLayout_LeftToRight, "Inupiak")
|
||||
LNG(wxLANGUAGE_IRISH, "ga_IE", 0 , 0 , wxLayout_LeftToRight, "Irish")
|
||||
LNG(wxLANGUAGE_ITALIAN, "it_IT", LANG_ITALIAN , SUBLANG_ITALIAN , wxLayout_LeftToRight, "Italian")
|
||||
LNG(wxLANGUAGE_ITALIAN_SWISS, "it_CH", LANG_ITALIAN , SUBLANG_ITALIAN_SWISS , wxLayout_LeftToRight, "Italian (Swiss)")
|
||||
LNG(wxLANGUAGE_JAPANESE, "ja_JP", LANG_JAPANESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Japanese")
|
||||
LNG(wxLANGUAGE_JAVANESE, "jv" , 0 , 0 , wxLayout_LeftToRight, "Javanese")
|
||||
LNG(wxLANGUAGE_KABYLE, "kab" , LANG_KABYLE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kabyle")
|
||||
LNG(wxLANGUAGE_KANNADA, "kn" , LANG_KANNADA , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kannada")
|
||||
LNG(wxLANGUAGE_KASHMIRI, "ks" , LANG_KASHMIRI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kashmiri")
|
||||
LNG(wxLANGUAGE_KASHMIRI_INDIA, "ks_IN", LANG_KASHMIRI , SUBLANG_KASHMIRI_INDIA , wxLayout_LeftToRight, "Kashmiri (India)")
|
||||
LNG(wxLANGUAGE_KAZAKH, "kk" , LANG_KAZAK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kazakh")
|
||||
LNG(wxLANGUAGE_KERNEWEK, "kw_GB", 0 , 0 , wxLayout_LeftToRight, "Kernewek")
|
||||
LNG(wxLANGUAGE_KHMER, "km" , 0 , 0 , wxLayout_LeftToRight, "Khmer")
|
||||
LNG(wxLANGUAGE_KINYARWANDA, "rw" , 0 , 0 , wxLayout_LeftToRight, "Kinyarwanda")
|
||||
LNG(wxLANGUAGE_KIRGHIZ, "ky" , 0 , 0 , wxLayout_LeftToRight, "Kirghiz")
|
||||
LNG(wxLANGUAGE_KIRUNDI, "rn" , 0 , 0 , wxLayout_LeftToRight, "Kirundi")
|
||||
LNG(wxLANGUAGE_KONKANI, "" , LANG_KONKANI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Konkani")
|
||||
LNG(wxLANGUAGE_KOREAN, "ko_KR", LANG_KOREAN , SUBLANG_KOREAN , wxLayout_LeftToRight, "Korean")
|
||||
LNG(wxLANGUAGE_KURDISH, "ku_TR", 0 , 0 , wxLayout_LeftToRight, "Kurdish")
|
||||
LNG(wxLANGUAGE_LAOTHIAN, "lo" , 0 , 0 , wxLayout_LeftToRight, "Laothian")
|
||||
LNG(wxLANGUAGE_LATIN, "la" , 0 , 0 , wxLayout_LeftToRight, "Latin")
|
||||
LNG(wxLANGUAGE_LATVIAN, "lv_LV", LANG_LATVIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Latvian")
|
||||
LNG(wxLANGUAGE_LINGALA, "ln" , 0 , 0 , wxLayout_LeftToRight, "Lingala")
|
||||
LNG(wxLANGUAGE_LITHUANIAN, "lt_LT", LANG_LITHUANIAN, SUBLANG_LITHUANIAN , wxLayout_LeftToRight, "Lithuanian")
|
||||
LNG(wxLANGUAGE_MACEDONIAN, "mk_MK", LANG_MACEDONIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Macedonian")
|
||||
LNG(wxLANGUAGE_MALAGASY, "mg" , 0 , 0 , wxLayout_LeftToRight, "Malagasy")
|
||||
LNG(wxLANGUAGE_MALAY, "ms_MY", LANG_MALAY , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Malay")
|
||||
LNG(wxLANGUAGE_MALAYALAM, "ml" , LANG_MALAYALAM , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Malayalam")
|
||||
LNG(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM, "ms_BN", LANG_MALAY , SUBLANG_MALAY_BRUNEI_DARUSSALAM , wxLayout_LeftToRight, "Malay (Brunei Darussalam)")
|
||||
LNG(wxLANGUAGE_MALAY_MALAYSIA, "ms_MY", LANG_MALAY , SUBLANG_MALAY_MALAYSIA , wxLayout_LeftToRight, "Malay (Malaysia)")
|
||||
LNG(wxLANGUAGE_MALTESE, "mt_MT", 0 , 0 , wxLayout_LeftToRight, "Maltese")
|
||||
LNG(wxLANGUAGE_MANIPURI, "" , LANG_MANIPURI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Manipuri")
|
||||
LNG(wxLANGUAGE_MAORI, "mi" , 0 , 0 , wxLayout_LeftToRight, "Maori")
|
||||
LNG(wxLANGUAGE_MARATHI, "mr_IN", LANG_MARATHI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Marathi")
|
||||
LNG(wxLANGUAGE_MOLDAVIAN, "mo" , 0 , 0 , wxLayout_LeftToRight, "Moldavian")
|
||||
LNG(wxLANGUAGE_MONGOLIAN, "mn" , 0 , 0 , wxLayout_LeftToRight, "Mongolian")
|
||||
LNG(wxLANGUAGE_NAURU, "na" , 0 , 0 , wxLayout_LeftToRight, "Nauru")
|
||||
LNG(wxLANGUAGE_NEPALI, "ne_NP", LANG_NEPALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Nepali")
|
||||
LNG(wxLANGUAGE_NEPALI_INDIA, "ne_IN", LANG_NEPALI , SUBLANG_NEPALI_INDIA , wxLayout_LeftToRight, "Nepali (India)")
|
||||
LNG(wxLANGUAGE_NORWEGIAN_BOKMAL, "nb_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_BOKMAL , wxLayout_LeftToRight, "Norwegian (Bokmal)")
|
||||
LNG(wxLANGUAGE_NORWEGIAN_NYNORSK, "nn_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_NYNORSK , wxLayout_LeftToRight, "Norwegian (Nynorsk)")
|
||||
LNG(wxLANGUAGE_OCCITAN, "oc" , 0 , 0 , wxLayout_LeftToRight, "Occitan")
|
||||
LNG(wxLANGUAGE_ORIYA, "or" , LANG_ORIYA , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Oriya")
|
||||
LNG(wxLANGUAGE_OROMO, "om" , 0 , 0 , wxLayout_LeftToRight, "(Afan) Oromo")
|
||||
LNG(wxLANGUAGE_PASHTO, "ps" , 0 , 0 , wxLayout_LeftToRight, "Pashto, Pushto")
|
||||
LNG(wxLANGUAGE_POLISH, "pl_PL", LANG_POLISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Polish")
|
||||
LNG(wxLANGUAGE_PORTUGUESE, "pt_PT", LANG_PORTUGUESE, SUBLANG_PORTUGUESE , wxLayout_LeftToRight, "Portuguese")
|
||||
LNG(wxLANGUAGE_PORTUGUESE_BRAZILIAN, "pt_BR", LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN , wxLayout_LeftToRight, "Portuguese (Brazilian)")
|
||||
LNG(wxLANGUAGE_PUNJABI, "pa" , LANG_PUNJABI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Punjabi")
|
||||
LNG(wxLANGUAGE_QUECHUA, "qu" , 0 , 0 , wxLayout_LeftToRight, "Quechua")
|
||||
LNG(wxLANGUAGE_RHAETO_ROMANCE, "rm" , 0 , 0 , wxLayout_LeftToRight, "Rhaeto-Romance")
|
||||
LNG(wxLANGUAGE_ROMANIAN, "ro_RO", LANG_ROMANIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Romanian")
|
||||
LNG(wxLANGUAGE_RUSSIAN, "ru_RU", LANG_RUSSIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Russian")
|
||||
LNG(wxLANGUAGE_RUSSIAN_UKRAINE, "ru_UA", 0 , 0 , wxLayout_LeftToRight, "Russian (Ukraine)")
|
||||
LNG(wxLANGUAGE_SAMI, "se_NO", LANG_SAMI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Northern Sami")
|
||||
LNG(wxLANGUAGE_SAMOAN, "sm" , 0 , 0 , wxLayout_LeftToRight, "Samoan")
|
||||
LNG(wxLANGUAGE_SANGHO, "sg" , 0 , 0 , wxLayout_LeftToRight, "Sangho")
|
||||
LNG(wxLANGUAGE_SANSKRIT, "sa" , LANG_SANSKRIT , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Sanskrit")
|
||||
LNG(wxLANGUAGE_SCOTS_GAELIC, "gd" , 0 , 0 , wxLayout_LeftToRight, "Scots Gaelic")
|
||||
LNG(wxLANGUAGE_SERBIAN, "sr_RS", LANG_SERBIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Serbian")
|
||||
LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_RS", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)")
|
||||
LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_RS@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)")
|
||||
LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_YU", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)")
|
||||
LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_YU@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)")
|
||||
LNG(wxLANGUAGE_SERBO_CROATIAN, "sh" , 0 , 0 , wxLayout_LeftToRight, "Serbo-Croatian")
|
||||
LNG(wxLANGUAGE_SESOTHO, "st" , 0 , 0 , wxLayout_LeftToRight, "Sesotho")
|
||||
LNG(wxLANGUAGE_SETSWANA, "tn" , 0 , 0 , wxLayout_LeftToRight, "Setswana")
|
||||
LNG(wxLANGUAGE_SHONA, "sn" , 0 , 0 , wxLayout_LeftToRight, "Shona")
|
||||
LNG(wxLANGUAGE_SINDHI, "sd" , LANG_SINDHI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Sindhi")
|
||||
LNG(wxLANGUAGE_SINHALESE, "si" , 0 , 0 , wxLayout_LeftToRight, "Sinhalese")
|
||||
LNG(wxLANGUAGE_SISWATI, "ss" , 0 , 0 , wxLayout_LeftToRight, "Siswati")
|
||||
LNG(wxLANGUAGE_SLOVAK, "sk_SK", LANG_SLOVAK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Slovak")
|
||||
LNG(wxLANGUAGE_SLOVENIAN, "sl_SI", LANG_SLOVENIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Slovenian")
|
||||
LNG(wxLANGUAGE_SOMALI, "so" , 0 , 0 , wxLayout_LeftToRight, "Somali")
|
||||
LNG(wxLANGUAGE_SPANISH, "es_ES", LANG_SPANISH , SUBLANG_SPANISH , wxLayout_LeftToRight, "Spanish")
|
||||
LNG(wxLANGUAGE_SPANISH_ARGENTINA, "es_AR", LANG_SPANISH , SUBLANG_SPANISH_ARGENTINA , wxLayout_LeftToRight, "Spanish (Argentina)")
|
||||
LNG(wxLANGUAGE_SPANISH_BOLIVIA, "es_BO", LANG_SPANISH , SUBLANG_SPANISH_BOLIVIA , wxLayout_LeftToRight, "Spanish (Bolivia)")
|
||||
LNG(wxLANGUAGE_SPANISH_CHILE, "es_CL", LANG_SPANISH , SUBLANG_SPANISH_CHILE , wxLayout_LeftToRight, "Spanish (Chile)")
|
||||
LNG(wxLANGUAGE_SPANISH_COLOMBIA, "es_CO", LANG_SPANISH , SUBLANG_SPANISH_COLOMBIA , wxLayout_LeftToRight, "Spanish (Colombia)")
|
||||
LNG(wxLANGUAGE_SPANISH_COSTA_RICA, "es_CR", LANG_SPANISH , SUBLANG_SPANISH_COSTA_RICA , wxLayout_LeftToRight, "Spanish (Costa Rica)")
|
||||
LNG(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, "es_DO", LANG_SPANISH , SUBLANG_SPANISH_DOMINICAN_REPUBLIC, wxLayout_LeftToRight, "Spanish (Dominican republic)")
|
||||
LNG(wxLANGUAGE_SPANISH_ECUADOR, "es_EC", LANG_SPANISH , SUBLANG_SPANISH_ECUADOR , wxLayout_LeftToRight, "Spanish (Ecuador)")
|
||||
LNG(wxLANGUAGE_SPANISH_EL_SALVADOR, "es_SV", LANG_SPANISH , SUBLANG_SPANISH_EL_SALVADOR , wxLayout_LeftToRight, "Spanish (El Salvador)")
|
||||
LNG(wxLANGUAGE_SPANISH_GUATEMALA, "es_GT", LANG_SPANISH , SUBLANG_SPANISH_GUATEMALA , wxLayout_LeftToRight, "Spanish (Guatemala)")
|
||||
LNG(wxLANGUAGE_SPANISH_HONDURAS, "es_HN", LANG_SPANISH , SUBLANG_SPANISH_HONDURAS , wxLayout_LeftToRight, "Spanish (Honduras)")
|
||||
LNG(wxLANGUAGE_SPANISH_MEXICAN, "es_MX", LANG_SPANISH , SUBLANG_SPANISH_MEXICAN , wxLayout_LeftToRight, "Spanish (Mexican)")
|
||||
LNG(wxLANGUAGE_SPANISH_MODERN, "es_ES", LANG_SPANISH , SUBLANG_SPANISH_MODERN , wxLayout_LeftToRight, "Spanish (Modern)")
|
||||
LNG(wxLANGUAGE_SPANISH_NICARAGUA, "es_NI", LANG_SPANISH , SUBLANG_SPANISH_NICARAGUA , wxLayout_LeftToRight, "Spanish (Nicaragua)")
|
||||
LNG(wxLANGUAGE_SPANISH_PANAMA, "es_PA", LANG_SPANISH , SUBLANG_SPANISH_PANAMA , wxLayout_LeftToRight, "Spanish (Panama)")
|
||||
LNG(wxLANGUAGE_SPANISH_PARAGUAY, "es_PY", LANG_SPANISH , SUBLANG_SPANISH_PARAGUAY , wxLayout_LeftToRight, "Spanish (Paraguay)")
|
||||
LNG(wxLANGUAGE_SPANISH_PERU, "es_PE", LANG_SPANISH , SUBLANG_SPANISH_PERU , wxLayout_LeftToRight, "Spanish (Peru)")
|
||||
LNG(wxLANGUAGE_SPANISH_PUERTO_RICO, "es_PR", LANG_SPANISH , SUBLANG_SPANISH_PUERTO_RICO , wxLayout_LeftToRight, "Spanish (Puerto Rico)")
|
||||
LNG(wxLANGUAGE_SPANISH_URUGUAY, "es_UY", LANG_SPANISH , SUBLANG_SPANISH_URUGUAY , wxLayout_LeftToRight, "Spanish (Uruguay)")
|
||||
LNG(wxLANGUAGE_SPANISH_US, "es_US", 0 , 0 , wxLayout_LeftToRight, "Spanish (U.S.)")
|
||||
LNG(wxLANGUAGE_SPANISH_VENEZUELA, "es_VE", LANG_SPANISH , SUBLANG_SPANISH_VENEZUELA , wxLayout_LeftToRight, "Spanish (Venezuela)")
|
||||
LNG(wxLANGUAGE_SUNDANESE, "su" , 0 , 0 , wxLayout_LeftToRight, "Sundanese")
|
||||
LNG(wxLANGUAGE_SWAHILI, "sw_KE", LANG_SWAHILI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Swahili")
|
||||
LNG(wxLANGUAGE_SWEDISH, "sv_SE", LANG_SWEDISH , SUBLANG_SWEDISH , wxLayout_LeftToRight, "Swedish")
|
||||
LNG(wxLANGUAGE_SWEDISH_FINLAND, "sv_FI", LANG_SWEDISH , SUBLANG_SWEDISH_FINLAND , wxLayout_LeftToRight, "Swedish (Finland)")
|
||||
LNG(wxLANGUAGE_TAGALOG, "tl_PH", 0 , 0 , wxLayout_LeftToRight, "Tagalog")
|
||||
LNG(wxLANGUAGE_TAJIK, "tg" , 0 , 0 , wxLayout_LeftToRight, "Tajik")
|
||||
LNG(wxLANGUAGE_TAMIL, "ta" , LANG_TAMIL , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Tamil")
|
||||
LNG(wxLANGUAGE_TATAR, "tt" , LANG_TATAR , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Tatar")
|
||||
LNG(wxLANGUAGE_TELUGU, "te" , LANG_TELUGU , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Telugu")
|
||||
LNG(wxLANGUAGE_THAI, "th_TH", LANG_THAI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Thai")
|
||||
LNG(wxLANGUAGE_TIBETAN, "bo" , 0 , 0 , wxLayout_LeftToRight, "Tibetan")
|
||||
LNG(wxLANGUAGE_TIGRINYA, "ti" , 0 , 0 , wxLayout_LeftToRight, "Tigrinya")
|
||||
LNG(wxLANGUAGE_TONGA, "to" , 0 , 0 , wxLayout_LeftToRight, "Tonga")
|
||||
LNG(wxLANGUAGE_TSONGA, "ts" , 0 , 0 , wxLayout_LeftToRight, "Tsonga")
|
||||
LNG(wxLANGUAGE_TURKISH, "tr_TR", LANG_TURKISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Turkish")
|
||||
LNG(wxLANGUAGE_TURKMEN, "tk" , 0 , 0 , wxLayout_LeftToRight, "Turkmen")
|
||||
LNG(wxLANGUAGE_TWI, "tw" , 0 , 0 , wxLayout_LeftToRight, "Twi")
|
||||
LNG(wxLANGUAGE_UIGHUR, "ug" , 0 , 0 , wxLayout_LeftToRight, "Uighur")
|
||||
LNG(wxLANGUAGE_UKRAINIAN, "uk_UA", LANG_UKRAINIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Ukrainian")
|
||||
LNG(wxLANGUAGE_URDU, "ur" , LANG_URDU , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Urdu")
|
||||
LNG(wxLANGUAGE_URDU_INDIA, "ur_IN", LANG_URDU , SUBLANG_URDU_INDIA , wxLayout_LeftToRight, "Urdu (India)")
|
||||
LNG(wxLANGUAGE_URDU_PAKISTAN, "ur_PK", LANG_URDU , SUBLANG_URDU_PAKISTAN , wxLayout_LeftToRight, "Urdu (Pakistan)")
|
||||
LNG(wxLANGUAGE_UZBEK, "uz" , LANG_UZBEK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Uzbek")
|
||||
LNG(wxLANGUAGE_UZBEK_CYRILLIC, "uz" , LANG_UZBEK , SUBLANG_UZBEK_CYRILLIC , wxLayout_LeftToRight, "Uzbek (Cyrillic)")
|
||||
LNG(wxLANGUAGE_UZBEK_LATIN, "uz" , LANG_UZBEK , SUBLANG_UZBEK_LATIN , wxLayout_LeftToRight, "Uzbek (Latin)")
|
||||
LNG(wxLANGUAGE_VALENCIAN, "ca_ES@valencia", 0 , 0 , wxLayout_LeftToRight, "Valencian (Southern Catalan)")
|
||||
LNG(wxLANGUAGE_VIETNAMESE, "vi_VN", LANG_VIETNAMESE, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Vietnamese")
|
||||
LNG(wxLANGUAGE_VOLAPUK, "vo" , 0 , 0 , wxLayout_LeftToRight, "Volapuk")
|
||||
LNG(wxLANGUAGE_WELSH, "cy" , 0 , 0 , wxLayout_LeftToRight, "Welsh")
|
||||
LNG(wxLANGUAGE_WOLOF, "wo" , 0 , 0 , wxLayout_LeftToRight, "Wolof")
|
||||
LNG(wxLANGUAGE_XHOSA, "xh" , 0 , 0 , wxLayout_LeftToRight, "Xhosa")
|
||||
LNG(wxLANGUAGE_YIDDISH, "yi" , 0 , 0 , wxLayout_LeftToRight, "Yiddish")
|
||||
LNG(wxLANGUAGE_YORUBA, "yo" , 0 , 0 , wxLayout_LeftToRight, "Yoruba")
|
||||
LNG(wxLANGUAGE_ZHUANG, "za" , 0 , 0 , wxLayout_LeftToRight, "Zhuang")
|
||||
LNG(wxLANGUAGE_ZULU, "zu" , 0 , 0 , wxLayout_LeftToRight, "Zulu")
|
||||
|
||||
}
|
||||
#undef LNG
|
||||
|
||||
// --- --- --- generated code ends here --- --- ---
|
||||
|
||||
#endif // wxUSE_INTL
|
||||
@@ -0,0 +1,745 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/list.cpp
|
||||
// Purpose: wxList implementation
|
||||
// Author: Julian Smart
|
||||
// Modified by: VZ at 16/11/98: WX_DECLARE_LIST() and typesafe lists added
|
||||
// Created: 04/01/98
|
||||
// Copyright: (c) Julian Smart
|
||||
// Licence: wxWindows licence
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// =============================================================================
|
||||
// declarations
|
||||
// =============================================================================
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// headers
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/list.h"
|
||||
#include "wx/crt.h"
|
||||
#endif
|
||||
|
||||
#if !wxUSE_STD_CONTAINERS
|
||||
|
||||
// =============================================================================
|
||||
// implementation
|
||||
// =============================================================================
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// wxListKey
|
||||
// -----------------------------------------------------------------------------
|
||||
wxListKey wxDefaultListKey;
|
||||
|
||||
bool wxListKey::operator==(wxListKeyValue value) const
|
||||
{
|
||||
switch ( m_keyType )
|
||||
{
|
||||
default:
|
||||
wxFAIL_MSG(wxT("bad key type."));
|
||||
// let compiler optimize the line above away in release build
|
||||
// by not putting return here...
|
||||
wxFALLTHROUGH;
|
||||
|
||||
case wxKEY_STRING:
|
||||
return *m_key.string == *value.string;
|
||||
|
||||
case wxKEY_INTEGER:
|
||||
return m_key.integer == value.integer;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// wxNodeBase
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
wxNodeBase::wxNodeBase(wxListBase *list,
|
||||
wxNodeBase *previous, wxNodeBase *next,
|
||||
void *data, const wxListKey& key)
|
||||
{
|
||||
m_list = list;
|
||||
m_data = data;
|
||||
m_previous = previous;
|
||||
m_next = next;
|
||||
|
||||
switch ( key.GetKeyType() )
|
||||
{
|
||||
case wxKEY_NONE:
|
||||
break;
|
||||
|
||||
case wxKEY_INTEGER:
|
||||
m_key.integer = key.GetNumber();
|
||||
break;
|
||||
|
||||
case wxKEY_STRING:
|
||||
// to be free()d later
|
||||
m_key.string = new wxString(key.GetString());
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG(wxT("invalid key type"));
|
||||
}
|
||||
|
||||
if ( previous )
|
||||
previous->m_next = this;
|
||||
|
||||
if ( next )
|
||||
next->m_previous = this;
|
||||
}
|
||||
|
||||
wxNodeBase::~wxNodeBase()
|
||||
{
|
||||
// handle the case when we're being deleted from the list by the user (i.e.
|
||||
// not by the list itself from DeleteNode) - we must do it for
|
||||
// compatibility with old code
|
||||
if ( m_list != NULL )
|
||||
{
|
||||
if ( m_list->m_keyType == wxKEY_STRING )
|
||||
{
|
||||
delete m_key.string;
|
||||
}
|
||||
|
||||
m_list->DetachNode(this);
|
||||
}
|
||||
}
|
||||
|
||||
int wxNodeBase::IndexOf() const
|
||||
{
|
||||
wxCHECK_MSG( m_list, wxNOT_FOUND, wxT("node doesn't belong to a list in IndexOf"));
|
||||
|
||||
// It would be more efficient to implement IndexOf() completely inside
|
||||
// wxListBase (only traverse the list once), but this is probably a more
|
||||
// reusable way of doing it. Can always be optimized at a later date (since
|
||||
// IndexOf() resides in wxListBase as well) if efficiency is a problem.
|
||||
int i;
|
||||
wxNodeBase *prev = m_previous;
|
||||
|
||||
for( i = 0; prev; i++ )
|
||||
{
|
||||
prev = prev->m_previous;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// wxListBase
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void wxListBase::Init(wxKeyType keyType)
|
||||
{
|
||||
m_nodeFirst =
|
||||
m_nodeLast = NULL;
|
||||
m_count = 0;
|
||||
m_destroy = false;
|
||||
m_keyType = keyType;
|
||||
}
|
||||
|
||||
void wxListBase::DoCopy(const wxListBase& list)
|
||||
{
|
||||
wxASSERT_MSG( !list.m_destroy,
|
||||
wxT("copying list which owns it's elements is a bad idea") );
|
||||
|
||||
m_destroy = list.m_destroy;
|
||||
m_keyType = list.m_keyType;
|
||||
m_nodeFirst =
|
||||
m_nodeLast = NULL;
|
||||
|
||||
switch (m_keyType)
|
||||
{
|
||||
case wxKEY_INTEGER:
|
||||
{
|
||||
for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
Append(node->GetKeyInteger(), node->GetData());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case wxKEY_STRING:
|
||||
{
|
||||
for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
Append(node->GetKeyString(), node->GetData());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
Append(node->GetData());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wxASSERT_MSG( m_count == list.m_count, wxT("logic error in wxList::DoCopy") );
|
||||
}
|
||||
|
||||
wxListBase::~wxListBase()
|
||||
{
|
||||
wxNodeBase *each = m_nodeFirst;
|
||||
while ( each != NULL )
|
||||
{
|
||||
wxNodeBase *next = each->GetNext();
|
||||
DoDeleteNode(each);
|
||||
each = next;
|
||||
}
|
||||
}
|
||||
|
||||
wxNodeBase *wxListBase::AppendCommon(wxNodeBase *node)
|
||||
{
|
||||
if ( !m_nodeFirst )
|
||||
{
|
||||
m_nodeFirst = node;
|
||||
m_nodeLast = m_nodeFirst;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nodeLast->m_next = node;
|
||||
m_nodeLast = node;
|
||||
}
|
||||
|
||||
m_count++;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
wxNodeBase *wxListBase::Append(void *object)
|
||||
{
|
||||
// all objects in a keyed list should have a key
|
||||
wxCHECK_MSG( m_keyType == wxKEY_NONE, NULL,
|
||||
wxT("need a key for the object to append") );
|
||||
|
||||
// we use wxDefaultListKey even though it is the default parameter value
|
||||
// because gcc under Mac OS X seems to miscompile this call otherwise
|
||||
wxNodeBase *node = CreateNode(m_nodeLast, NULL, object,
|
||||
wxDefaultListKey);
|
||||
|
||||
return AppendCommon(node);
|
||||
}
|
||||
|
||||
wxNodeBase *wxListBase::Append(long key, void *object)
|
||||
{
|
||||
wxCHECK_MSG( (m_keyType == wxKEY_INTEGER) ||
|
||||
(m_keyType == wxKEY_NONE && m_count == 0),
|
||||
NULL,
|
||||
wxT("can't append object with numeric key to this list") );
|
||||
|
||||
wxNodeBase *node = CreateNode(m_nodeLast, NULL, object, key);
|
||||
return AppendCommon(node);
|
||||
}
|
||||
|
||||
wxNodeBase *wxListBase::Append (const wxString& key, void *object)
|
||||
{
|
||||
wxCHECK_MSG( (m_keyType == wxKEY_STRING) ||
|
||||
(m_keyType == wxKEY_NONE && m_count == 0),
|
||||
NULL,
|
||||
wxT("can't append object with string key to this list") );
|
||||
|
||||
wxNodeBase *node = CreateNode(m_nodeLast, NULL, object, key);
|
||||
return AppendCommon(node);
|
||||
}
|
||||
|
||||
wxNodeBase *wxListBase::Insert(wxNodeBase *position, void *object)
|
||||
{
|
||||
// all objects in a keyed list should have a key
|
||||
wxCHECK_MSG( m_keyType == wxKEY_NONE, NULL,
|
||||
wxT("need a key for the object to insert") );
|
||||
|
||||
wxCHECK_MSG( !position || position->m_list == this, NULL,
|
||||
wxT("can't insert before a node from another list") );
|
||||
|
||||
// previous and next node for the node being inserted
|
||||
wxNodeBase *prev, *next;
|
||||
if ( position )
|
||||
{
|
||||
prev = position->GetPrevious();
|
||||
next = position;
|
||||
}
|
||||
else
|
||||
{
|
||||
// inserting in the beginning of the list
|
||||
prev = NULL;
|
||||
next = m_nodeFirst;
|
||||
}
|
||||
|
||||
// wxDefaultListKey: see comment in Append() above
|
||||
wxNodeBase *node = CreateNode(prev, next, object, wxDefaultListKey);
|
||||
if ( !m_nodeFirst )
|
||||
{
|
||||
m_nodeLast = node;
|
||||
}
|
||||
|
||||
if ( prev == NULL )
|
||||
{
|
||||
m_nodeFirst = node;
|
||||
}
|
||||
|
||||
m_count++;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
wxNodeBase *wxListBase::Item(size_t n) const
|
||||
{
|
||||
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
|
||||
{
|
||||
if ( n-- == 0 )
|
||||
{
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
wxFAIL_MSG( wxT("invalid index in wxListBase::Item") );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wxNodeBase *wxListBase::Find(const wxListKey& key) const
|
||||
{
|
||||
wxASSERT_MSG( m_keyType == key.GetKeyType(),
|
||||
wxT("this list is not keyed on the type of this key") );
|
||||
|
||||
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
|
||||
{
|
||||
if ( key == current->m_key )
|
||||
{
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
// not found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wxNodeBase *wxListBase::Find(const void *object) const
|
||||
{
|
||||
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
|
||||
{
|
||||
if ( current->GetData() == object )
|
||||
return current;
|
||||
}
|
||||
|
||||
// not found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int wxListBase::IndexOf(void *object) const
|
||||
{
|
||||
wxNodeBase *node = Find( object );
|
||||
|
||||
return node ? node->IndexOf() : wxNOT_FOUND;
|
||||
}
|
||||
|
||||
void wxListBase::DoDeleteNode(wxNodeBase *node)
|
||||
{
|
||||
// free node's data
|
||||
if ( m_keyType == wxKEY_STRING )
|
||||
{
|
||||
wxDELETE(node->m_key.string);
|
||||
}
|
||||
|
||||
if ( m_destroy )
|
||||
{
|
||||
node->DeleteData();
|
||||
}
|
||||
|
||||
// so that the node knows that it's being deleted by the list
|
||||
node->m_list = NULL;
|
||||
delete node;
|
||||
}
|
||||
|
||||
wxNodeBase *wxListBase::DetachNode(wxNodeBase *node)
|
||||
{
|
||||
wxCHECK_MSG( node, NULL, wxT("detaching NULL wxNodeBase") );
|
||||
wxCHECK_MSG( node->m_list == this, NULL,
|
||||
wxT("detaching node which is not from this list") );
|
||||
|
||||
// update the list
|
||||
wxNodeBase **prevNext = node->GetPrevious() ? &node->GetPrevious()->m_next
|
||||
: &m_nodeFirst;
|
||||
wxNodeBase **nextPrev = node->GetNext() ? &node->GetNext()->m_previous
|
||||
: &m_nodeLast;
|
||||
|
||||
*prevNext = node->GetNext();
|
||||
*nextPrev = node->GetPrevious();
|
||||
|
||||
m_count--;
|
||||
|
||||
// mark the node as not belonging to this list any more
|
||||
node->m_list = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
bool wxListBase::DeleteNode(wxNodeBase *node)
|
||||
{
|
||||
if ( !DetachNode(node) )
|
||||
return false;
|
||||
|
||||
DoDeleteNode(node);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxListBase::DeleteObject(void *object)
|
||||
{
|
||||
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
|
||||
{
|
||||
if ( current->GetData() == object )
|
||||
{
|
||||
DeleteNode(current);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// not found
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxListBase::Clear()
|
||||
{
|
||||
wxNodeBase *current = m_nodeFirst;
|
||||
while ( current )
|
||||
{
|
||||
wxNodeBase *next = current->GetNext();
|
||||
DoDeleteNode(current);
|
||||
current = next;
|
||||
}
|
||||
|
||||
m_nodeFirst =
|
||||
m_nodeLast = NULL;
|
||||
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
void wxListBase::ForEach(wxListIterateFunction F)
|
||||
{
|
||||
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
|
||||
{
|
||||
(*F)(current->GetData());
|
||||
}
|
||||
}
|
||||
|
||||
void *wxListBase::FirstThat(wxListIterateFunction F)
|
||||
{
|
||||
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
|
||||
{
|
||||
if ( (*F)(current->GetData()) )
|
||||
return current->GetData();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *wxListBase::LastThat(wxListIterateFunction F)
|
||||
{
|
||||
for ( wxNodeBase *current = GetLast(); current; current = current->GetPrevious() )
|
||||
{
|
||||
if ( (*F)(current->GetData()) )
|
||||
return current->GetData();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// (stefan.hammes@urz.uni-heidelberg.de)
|
||||
//
|
||||
// function for sorting lists. the concept is borrowed from 'qsort'.
|
||||
// by giving a sort function, arbitrary lists can be sorted.
|
||||
// method:
|
||||
// - put wxObject pointers into an array
|
||||
// - sort the array with qsort
|
||||
// - put back the sorted wxObject pointers into the list
|
||||
//
|
||||
// CAVE: the sort function receives pointers to wxObject pointers (wxObject **),
|
||||
// so dereference right!
|
||||
// EXAMPLE:
|
||||
// int listcompare(const void *arg1, const void *arg2)
|
||||
// {
|
||||
// return(compare(**(wxString **)arg1,
|
||||
// **(wxString **)arg2));
|
||||
// }
|
||||
//
|
||||
// void main()
|
||||
// {
|
||||
// wxListBase list;
|
||||
//
|
||||
// list.Append(new wxString("DEF"));
|
||||
// list.Append(new wxString("GHI"));
|
||||
// list.Append(new wxString("ABC"));
|
||||
// list.Sort(listcompare);
|
||||
// }
|
||||
|
||||
void wxListBase::Sort(const wxSortCompareFunction compfunc)
|
||||
{
|
||||
// allocate an array for the wxObject pointers of the list
|
||||
const size_t num = GetCount();
|
||||
void **objArray = new void *[num];
|
||||
void **objPtr = objArray;
|
||||
|
||||
// go through the list and put the pointers into the array
|
||||
wxNodeBase *node;
|
||||
for ( node = GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
*objPtr++ = node->GetData();
|
||||
}
|
||||
|
||||
// sort the array
|
||||
qsort((void *)objArray,num,sizeof(wxObject *),
|
||||
compfunc);
|
||||
|
||||
// put the sorted pointers back into the list
|
||||
objPtr = objArray;
|
||||
for ( node = GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
node->SetData(*objPtr++);
|
||||
}
|
||||
|
||||
// free the array
|
||||
delete[] objArray;
|
||||
}
|
||||
|
||||
void wxListBase::Reverse()
|
||||
{
|
||||
wxNodeBase* node = m_nodeFirst;
|
||||
wxNodeBase* tmp;
|
||||
|
||||
while (node)
|
||||
{
|
||||
// swap prev and next pointers
|
||||
tmp = node->m_next;
|
||||
node->m_next = node->m_previous;
|
||||
node->m_previous = tmp;
|
||||
|
||||
// this is the node that was next before swapping
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
// swap first and last node
|
||||
tmp = m_nodeFirst; m_nodeFirst = m_nodeLast; m_nodeLast = tmp;
|
||||
}
|
||||
|
||||
void wxListBase::DeleteNodes(wxNodeBase* first, wxNodeBase* last)
|
||||
{
|
||||
wxNodeBase* node = first;
|
||||
|
||||
while (node != last)
|
||||
{
|
||||
wxNodeBase* next = node->GetNext();
|
||||
DeleteNode(node);
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// compatibility section from now on
|
||||
// ============================================================================
|
||||
|
||||
#ifdef wxLIST_COMPATIBILITY
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// wxList (a.k.a. wxObjectList)
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
wxList::wxList( int key_type )
|
||||
: wxObjectList( (wxKeyType)key_type )
|
||||
{
|
||||
}
|
||||
|
||||
void wxObjectListNode::DeleteData()
|
||||
{
|
||||
delete (wxObject *)GetData();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxStringList
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static inline wxChar* MYcopystring(const wxChar* s)
|
||||
{
|
||||
wxChar* copy = new wxChar[wxStrlen(s) + 1];
|
||||
return wxStrcpy(copy, s);
|
||||
}
|
||||
|
||||
// instead of WX_DEFINE_LIST(wxStringListBase) we define this function
|
||||
// ourselves
|
||||
void wxStringListNode::DeleteData()
|
||||
{
|
||||
delete [] (char *)GetData();
|
||||
}
|
||||
|
||||
bool wxStringList::Delete(const wxChar *s)
|
||||
{
|
||||
wxStringListNode *current;
|
||||
|
||||
for ( current = GetFirst(); current; current = current->GetNext() )
|
||||
{
|
||||
if ( wxStrcmp(current->GetData(), s) == 0 )
|
||||
{
|
||||
DeleteNode(current);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// not found
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxStringList::DoCopy(const wxStringList& other)
|
||||
{
|
||||
wxASSERT( GetCount() == 0 ); // this list must be empty before copying!
|
||||
|
||||
size_t count = other.GetCount();
|
||||
for ( size_t n = 0; n < count; n++ )
|
||||
{
|
||||
Add(other.Item(n)->GetData());
|
||||
}
|
||||
}
|
||||
|
||||
wxStringList::wxStringList()
|
||||
{
|
||||
DeleteContents(true);
|
||||
}
|
||||
|
||||
// Variable argument list, terminated by a zero
|
||||
// Makes new storage for the strings
|
||||
wxStringList::wxStringList (const wxChar *first, ...)
|
||||
{
|
||||
DeleteContents(true);
|
||||
if ( !first )
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, first);
|
||||
|
||||
const wxChar *s = first;
|
||||
for (;;)
|
||||
{
|
||||
Add(s);
|
||||
|
||||
// icc gives this warning in its own va_arg() macro, argh
|
||||
#ifdef __INTELC__
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 1684)
|
||||
#endif
|
||||
|
||||
s = va_arg(ap, const wxChar *);
|
||||
|
||||
#ifdef __INTELC__
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
if ( !s )
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// Only makes new strings if arg is true
|
||||
wxChar **wxStringList::ListToArray(bool new_copies) const
|
||||
{
|
||||
wxChar **string_array = new wxChar *[GetCount()];
|
||||
wxStringListNode *node = GetFirst();
|
||||
for (size_t i = 0; i < GetCount(); i++)
|
||||
{
|
||||
wxChar *s = node->GetData();
|
||||
if ( new_copies )
|
||||
string_array[i] = MYcopystring(s);
|
||||
else
|
||||
string_array[i] = s;
|
||||
node = node->GetNext();
|
||||
}
|
||||
|
||||
return string_array;
|
||||
}
|
||||
|
||||
// Checks whether s is a member of the list
|
||||
bool wxStringList::Member(const wxChar *s) const
|
||||
{
|
||||
for ( wxStringListNode *node = GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
const wxChar *s1 = node->GetData();
|
||||
if (s == s1 || wxStrcmp (s, s1) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static int LINKAGEMODE
|
||||
|
||||
wx_comparestrings(const void *arg1, const void *arg2)
|
||||
{
|
||||
const wxChar* s1 = *static_cast<wxChar* const*>(arg1);
|
||||
const wxChar* s2 = *static_cast<wxChar* const*>(arg2);
|
||||
|
||||
return wxStrcmp(s1, s2);
|
||||
}
|
||||
|
||||
} // end of extern "C" (required because of GCC Bug c++/33078
|
||||
|
||||
// Sort a list of strings - deallocates old nodes, allocates new
|
||||
void wxStringList::Sort()
|
||||
{
|
||||
size_t N = GetCount();
|
||||
wxChar **array = new wxChar *[N];
|
||||
wxStringListNode *node;
|
||||
|
||||
size_t i = 0;
|
||||
for ( node = GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
array[i++] = node->GetData();
|
||||
}
|
||||
|
||||
qsort (array, N, sizeof (wxChar *), wx_comparestrings);
|
||||
|
||||
i = 0;
|
||||
for ( node = GetFirst(); node; node = node->GetNext() )
|
||||
node->SetData( array[i++] );
|
||||
|
||||
delete [] array;
|
||||
}
|
||||
|
||||
wxNode *wxStringList::Add(const wxChar *s)
|
||||
{
|
||||
return (wxNode *)(wxStringListBase::Node *)
|
||||
wxStringListBase::Append(MYcopystring(s));
|
||||
}
|
||||
|
||||
wxNode *wxStringList::Prepend(const wxChar *s)
|
||||
{
|
||||
return (wxNode *)(wxStringListBase::Node *)
|
||||
wxStringListBase::Insert(MYcopystring(s));
|
||||
}
|
||||
|
||||
#endif // wxLIST_COMPATIBILITY
|
||||
|
||||
#else // wxUSE_STD_CONTAINERS = 1
|
||||
|
||||
#include "wx/listimpl.cpp"
|
||||
WX_DEFINE_LIST(wxObjectList)
|
||||
|
||||
// with wxUSE_STD_CONTAINERS wxStringList contains wxString objects, not pointers
|
||||
void _WX_LIST_HELPER_wxStringListBase::DeleteFunction( wxString WXUNUSED(X) )
|
||||
{
|
||||
}
|
||||
|
||||
_WX_LIST_HELPER_wxStringListBase::BaseListType _WX_LIST_HELPER_wxStringListBase::EmptyList;
|
||||
|
||||
#endif // !wxUSE_STD_CONTAINERS
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,403 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/lzmastream.cpp
|
||||
// Purpose: Implementation of LZMA stream classes
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2018-03-29
|
||||
// Copyright: (c) 2018 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_LIBLZMA && wxUSE_STREAMS
|
||||
|
||||
#include "wx/lzmastream.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/log.h"
|
||||
#include "wx/translation.h"
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include <lzma.h>
|
||||
|
||||
namespace wxPrivate
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const size_t wxLZMA_BUF_SIZE = 4096;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Private helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Simpler wrapper around lzma_stream, taking care of initializing and
|
||||
// finalizing it.
|
||||
struct wxLZMAStream : lzma_stream
|
||||
{
|
||||
wxLZMAStream()
|
||||
{
|
||||
memset(this, 0, sizeof(lzma_stream));
|
||||
}
|
||||
|
||||
~wxLZMAStream()
|
||||
{
|
||||
lzma_end(this);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace wxPrivate
|
||||
|
||||
using namespace wxPrivate;
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Functions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxVersionInfo wxGetLibLZMAVersionInfo()
|
||||
{
|
||||
const uint32_t ver = lzma_version_number();
|
||||
|
||||
// For now ignore the "stability" part of the version.
|
||||
return wxVersionInfo
|
||||
(
|
||||
"liblzma",
|
||||
ver / 10000000,
|
||||
(ver % 10000000) / 10000,
|
||||
(ver % 10000) / 10
|
||||
);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxLZMAData: common helpers for compression and decompression
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxLZMAData::wxLZMAData()
|
||||
{
|
||||
m_stream = new wxLZMAStream;
|
||||
m_streamBuf = new wxUint8[wxLZMA_BUF_SIZE];
|
||||
m_pos = 0;
|
||||
}
|
||||
|
||||
wxLZMAData::~wxLZMAData()
|
||||
{
|
||||
delete [] m_streamBuf;
|
||||
delete m_stream;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxLZMAInputStream: decompression
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxLZMAInputStream::Init()
|
||||
{
|
||||
// We don't specify any memory usage limit nor any flags, not even
|
||||
// LZMA_CONCATENATED recommended by liblzma documentation, because we don't
|
||||
// foresee the need to support concatenated compressed files for now.
|
||||
const lzma_ret rc = lzma_stream_decoder(m_stream, UINT64_MAX, 0);
|
||||
switch ( rc )
|
||||
{
|
||||
case LZMA_OK:
|
||||
// Skip setting m_lasterror below.
|
||||
return;
|
||||
|
||||
case LZMA_MEM_ERROR:
|
||||
wxLogError(_("Failed to allocate memory for LZMA decompression."));
|
||||
break;
|
||||
|
||||
default:
|
||||
wxLogError(_("Failed to initialize LZMA decompression: "
|
||||
"unexpected error %u."),
|
||||
rc);
|
||||
break;
|
||||
}
|
||||
|
||||
m_lasterror = wxSTREAM_READ_ERROR;
|
||||
}
|
||||
|
||||
size_t wxLZMAInputStream::OnSysRead(void* outbuf, size_t size)
|
||||
{
|
||||
m_stream->next_out = static_cast<uint8_t*>(outbuf);
|
||||
m_stream->avail_out = size;
|
||||
|
||||
// Decompress input as long as we don't have any errors (including EOF, as
|
||||
// it doesn't make sense to continue after it neither) and have space to
|
||||
// decompress it to.
|
||||
while ( m_lasterror == wxSTREAM_NO_ERROR && m_stream->avail_out > 0 )
|
||||
{
|
||||
// Get more input data if needed.
|
||||
if ( !m_stream->avail_in )
|
||||
{
|
||||
m_parent_i_stream->Read(m_streamBuf, wxLZMA_BUF_SIZE);
|
||||
m_stream->next_in = m_streamBuf;
|
||||
m_stream->avail_in = m_parent_i_stream->LastRead();
|
||||
|
||||
if ( !m_stream->avail_in )
|
||||
{
|
||||
if ( m_parent_i_stream->GetLastError() == wxSTREAM_EOF )
|
||||
{
|
||||
// We have reached end of the underlying stream.
|
||||
m_lasterror = wxSTREAM_EOF;
|
||||
break;
|
||||
}
|
||||
|
||||
m_lasterror = wxSTREAM_READ_ERROR;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Do decompress.
|
||||
const lzma_ret rc = lzma_code(m_stream, LZMA_RUN);
|
||||
|
||||
wxString err;
|
||||
switch ( rc )
|
||||
{
|
||||
case LZMA_OK:
|
||||
continue;
|
||||
|
||||
case LZMA_STREAM_END:
|
||||
m_lasterror = wxSTREAM_EOF;
|
||||
continue;
|
||||
|
||||
case LZMA_FORMAT_ERROR:
|
||||
err = wxTRANSLATE("input is not in XZ format");
|
||||
break;
|
||||
|
||||
case LZMA_OPTIONS_ERROR:
|
||||
err = wxTRANSLATE("input compressed using unknown XZ option");
|
||||
break;
|
||||
|
||||
case LZMA_DATA_ERROR:
|
||||
case LZMA_BUF_ERROR:
|
||||
err = wxTRANSLATE("input is corrupted");
|
||||
break;
|
||||
|
||||
default:
|
||||
err = wxTRANSLATE("unknown decompression error");
|
||||
break;
|
||||
}
|
||||
|
||||
wxLogError(_("LZMA decompression error: %s"), wxGetTranslation(err));
|
||||
|
||||
m_lasterror = wxSTREAM_READ_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return the number of bytes actually read, this may be less than the
|
||||
// requested size if we hit EOF.
|
||||
size -= m_stream->avail_out;
|
||||
m_pos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxLZMAOutputStream: compression
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxLZMAOutputStream::Init(int level)
|
||||
{
|
||||
if ( level == -1 )
|
||||
level = LZMA_PRESET_DEFAULT;
|
||||
|
||||
// Use the check type recommended by liblzma documentation.
|
||||
const lzma_ret rc = lzma_easy_encoder(m_stream, level, LZMA_CHECK_CRC64);
|
||||
switch ( rc )
|
||||
{
|
||||
case LZMA_OK:
|
||||
// Prepare for the first call to OnSysWrite().
|
||||
m_stream->next_out = m_streamBuf;
|
||||
m_stream->avail_out = wxLZMA_BUF_SIZE;
|
||||
|
||||
// Skip setting m_lasterror below.
|
||||
return;
|
||||
|
||||
case LZMA_MEM_ERROR:
|
||||
wxLogError(_("Failed to allocate memory for LZMA compression."));
|
||||
break;
|
||||
|
||||
default:
|
||||
wxLogError(_("Failed to initialize LZMA compression: "
|
||||
"unexpected error %u."),
|
||||
rc);
|
||||
break;
|
||||
}
|
||||
|
||||
m_lasterror = wxSTREAM_WRITE_ERROR;
|
||||
}
|
||||
|
||||
size_t wxLZMAOutputStream::OnSysWrite(const void *inbuf, size_t size)
|
||||
{
|
||||
m_stream->next_in = static_cast<const uint8_t*>(inbuf);
|
||||
m_stream->avail_in = size;
|
||||
|
||||
// Compress as long as we have any input data, but stop at first error as
|
||||
// it's useless to try to continue after it (or even starting if the stream
|
||||
// had already been in an error state).
|
||||
while ( m_lasterror == wxSTREAM_NO_ERROR && m_stream->avail_in > 0 )
|
||||
{
|
||||
// Flush the output buffer if necessary.
|
||||
if ( !UpdateOutputIfNecessary() )
|
||||
return 0;
|
||||
|
||||
const lzma_ret rc = lzma_code(m_stream, LZMA_RUN);
|
||||
|
||||
wxString err;
|
||||
switch ( rc )
|
||||
{
|
||||
case LZMA_OK:
|
||||
continue;
|
||||
|
||||
case LZMA_MEM_ERROR:
|
||||
err = wxTRANSLATE("out of memory");
|
||||
break;
|
||||
|
||||
case LZMA_STREAM_END:
|
||||
// This is unexpected as we don't use LZMA_FINISH here.
|
||||
wxFAIL_MSG( "Unexpected LZMA stream end" );
|
||||
wxFALLTHROUGH;
|
||||
|
||||
default:
|
||||
err = wxTRANSLATE("unknown compression error");
|
||||
break;
|
||||
}
|
||||
|
||||
wxLogError(_("LZMA compression error: %s"), wxGetTranslation(err));
|
||||
|
||||
m_lasterror = wxSTREAM_WRITE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_pos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
bool wxLZMAOutputStream::UpdateOutput()
|
||||
{
|
||||
// Write the buffer contents to the real output, taking care only to write
|
||||
// as much of it as we actually have, as the buffer can (and very likely
|
||||
// will) be incomplete.
|
||||
const size_t numOut = wxLZMA_BUF_SIZE - m_stream->avail_out;
|
||||
m_parent_o_stream->Write(m_streamBuf, numOut);
|
||||
if ( m_parent_o_stream->LastWrite() != numOut )
|
||||
{
|
||||
m_lasterror = wxSTREAM_WRITE_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxLZMAOutputStream::UpdateOutputIfNecessary()
|
||||
{
|
||||
if ( !m_stream->avail_out )
|
||||
{
|
||||
if ( !UpdateOutput() )
|
||||
return false;
|
||||
|
||||
m_stream->next_out = m_streamBuf;
|
||||
m_stream->avail_out = wxLZMA_BUF_SIZE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxLZMAOutputStream::DoFlush(bool finish)
|
||||
{
|
||||
const lzma_action action = finish ? LZMA_FINISH : LZMA_FULL_FLUSH;
|
||||
|
||||
while ( m_lasterror == wxSTREAM_NO_ERROR )
|
||||
{
|
||||
if ( !UpdateOutputIfNecessary() )
|
||||
break;
|
||||
|
||||
const lzma_ret rc = lzma_code(m_stream, action);
|
||||
|
||||
wxString err;
|
||||
switch ( rc )
|
||||
{
|
||||
case LZMA_OK:
|
||||
continue;
|
||||
|
||||
case LZMA_STREAM_END:
|
||||
// Don't forget to output the last part of the data.
|
||||
return UpdateOutput();
|
||||
|
||||
case LZMA_MEM_ERROR:
|
||||
err = wxTRANSLATE("out of memory");
|
||||
break;
|
||||
|
||||
default:
|
||||
err = wxTRANSLATE("unknown compression error");
|
||||
break;
|
||||
}
|
||||
|
||||
wxLogError(_("LZMA compression error when flushing output: %s"),
|
||||
wxGetTranslation(err));
|
||||
|
||||
m_lasterror = wxSTREAM_WRITE_ERROR;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wxLZMAOutputStream::Close()
|
||||
{
|
||||
if ( !DoFlush(true) )
|
||||
return false;
|
||||
|
||||
m_stream->next_out = m_streamBuf;
|
||||
m_stream->avail_out = wxLZMA_BUF_SIZE;
|
||||
|
||||
return wxFilterOutputStream::Close() && IsOk();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxLZMAClassFactory: allow creating streams from extension/MIME type
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxLZMAClassFactory, wxFilterClassFactory);
|
||||
|
||||
static wxLZMAClassFactory g_wxLZMAClassFactory;
|
||||
|
||||
wxLZMAClassFactory::wxLZMAClassFactory()
|
||||
{
|
||||
if ( this == &g_wxLZMAClassFactory )
|
||||
PushFront();
|
||||
}
|
||||
|
||||
const wxChar * const *
|
||||
wxLZMAClassFactory::GetProtocols(wxStreamProtocolType type) const
|
||||
{
|
||||
static const wxChar *mime[] = { wxT("application/xz"), NULL };
|
||||
static const wxChar *encs[] = { wxT("xz"), NULL };
|
||||
static const wxChar *exts[] = { wxT(".xz"), NULL };
|
||||
|
||||
const wxChar* const* ret = NULL;
|
||||
switch ( type )
|
||||
{
|
||||
case wxSTREAM_PROTOCOL: ret = encs; break;
|
||||
case wxSTREAM_MIMETYPE: ret = mime; break;
|
||||
case wxSTREAM_ENCODING: ret = encs; break;
|
||||
case wxSTREAM_FILEEXT: ret = exts; break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // wxUSE_LIBLZMA && wxUSE_STREAMS
|
||||
@@ -0,0 +1,601 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/matrix.cpp
|
||||
// Purpose: wxTransformMatrix class
|
||||
// Author: Chris Breeze, Julian Smart
|
||||
// Modified by: Klaas Holwerda
|
||||
// Created: 01/02/97
|
||||
// Copyright: (c) Julian Smart
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Note: this is intended to be used in wxDC at some point to replace
|
||||
// the current system of scaling/translation. It is not yet used.
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if WXWIN_COMPATIBILITY_3_0
|
||||
|
||||
#include "wx/matrix.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/math.h"
|
||||
#endif
|
||||
|
||||
static const double pi = M_PI;
|
||||
|
||||
wxTransformMatrix::wxTransformMatrix()
|
||||
{
|
||||
m_isIdentity = false;
|
||||
|
||||
Identity();
|
||||
}
|
||||
|
||||
wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat)
|
||||
: wxObject()
|
||||
{
|
||||
(*this) = mat;
|
||||
}
|
||||
|
||||
double wxTransformMatrix::GetValue(int col, int row) const
|
||||
{
|
||||
if (row < 0 || row > 2 || col < 0 || col > 2)
|
||||
return 0.0;
|
||||
|
||||
return m_matrix[col][row];
|
||||
}
|
||||
|
||||
void wxTransformMatrix::SetValue(int col, int row, double value)
|
||||
{
|
||||
if (row < 0 || row > 2 || col < 0 || col > 2)
|
||||
return;
|
||||
|
||||
m_matrix[col][row] = value;
|
||||
m_isIdentity = IsIdentity1();
|
||||
}
|
||||
|
||||
void wxTransformMatrix::operator = (const wxTransformMatrix& mat)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
m_matrix[i][j] = mat.m_matrix[i][j];
|
||||
}
|
||||
}
|
||||
m_isIdentity = mat.m_isIdentity;
|
||||
}
|
||||
|
||||
bool wxTransformMatrix::operator == (const wxTransformMatrix& mat) const
|
||||
{
|
||||
if (m_isIdentity && mat.m_isIdentity)
|
||||
return true;
|
||||
|
||||
int i, j;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
if ( !wxIsSameDouble(m_matrix[i][j], mat.m_matrix[i][j]) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const
|
||||
{
|
||||
return (! ((*this) == mat));
|
||||
}
|
||||
|
||||
double& wxTransformMatrix::operator()(int col, int row)
|
||||
{
|
||||
if (row < 0 || row > 2 || col < 0 || col > 2)
|
||||
return m_matrix[0][0];
|
||||
|
||||
return m_matrix[col][row];
|
||||
}
|
||||
|
||||
double wxTransformMatrix::operator()(int col, int row) const
|
||||
{
|
||||
if (row < 0 || row > 2 || col < 0 || col > 2)
|
||||
return 0.0;
|
||||
|
||||
return m_matrix[col][row];
|
||||
}
|
||||
|
||||
// Invert matrix
|
||||
bool wxTransformMatrix::Invert()
|
||||
{
|
||||
double inverseMatrix[3][3];
|
||||
|
||||
// calculate the adjoint
|
||||
inverseMatrix[0][0] = wxCalculateDet(m_matrix[1][1],m_matrix[2][1],m_matrix[1][2],m_matrix[2][2]);
|
||||
inverseMatrix[0][1] = -wxCalculateDet(m_matrix[0][1],m_matrix[2][1],m_matrix[0][2],m_matrix[2][2]);
|
||||
inverseMatrix[0][2] = wxCalculateDet(m_matrix[0][1],m_matrix[1][1],m_matrix[0][2],m_matrix[1][2]);
|
||||
|
||||
inverseMatrix[1][0] = -wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][2],m_matrix[2][2]);
|
||||
inverseMatrix[1][1] = wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][2],m_matrix[2][2]);
|
||||
inverseMatrix[1][2] = -wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][2],m_matrix[1][2]);
|
||||
|
||||
inverseMatrix[2][0] = wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][1],m_matrix[2][1]);
|
||||
inverseMatrix[2][1] = -wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][1],m_matrix[2][1]);
|
||||
inverseMatrix[2][2] = wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][1],m_matrix[1][1]);
|
||||
|
||||
// now divide by the determinant
|
||||
double det = m_matrix[0][0] * inverseMatrix[0][0] + m_matrix[0][1] * inverseMatrix[1][0] + m_matrix[0][2] * inverseMatrix[2][0];
|
||||
if ( wxIsNullDouble(det) )
|
||||
return false;
|
||||
|
||||
inverseMatrix[0][0] /= det; inverseMatrix[1][0] /= det; inverseMatrix[2][0] /= det;
|
||||
inverseMatrix[0][1] /= det; inverseMatrix[1][1] /= det; inverseMatrix[2][1] /= det;
|
||||
inverseMatrix[0][2] /= det; inverseMatrix[1][2] /= det; inverseMatrix[2][2] /= det;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
m_matrix[i][j] = inverseMatrix[i][j];
|
||||
}
|
||||
}
|
||||
m_isIdentity = IsIdentity1();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Make into identity matrix
|
||||
bool wxTransformMatrix::Identity()
|
||||
{
|
||||
m_matrix[0][0] = m_matrix[1][1] = m_matrix[2][2] = 1.0;
|
||||
m_matrix[1][0] = m_matrix[2][0] = m_matrix[0][1] = m_matrix[2][1] = m_matrix[0][2] = m_matrix[1][2] = 0.0;
|
||||
m_isIdentity = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Scale by scale (isotropic scaling i.e. the same in x and y):
|
||||
// | scale 0 0 |
|
||||
// matrix' = | 0 scale 0 | x matrix
|
||||
// | 0 0 scale |
|
||||
//
|
||||
bool wxTransformMatrix::Scale(double scale)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
m_matrix[i][j] *= scale;
|
||||
}
|
||||
}
|
||||
m_isIdentity = IsIdentity1();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// scale a matrix in 2D
|
||||
//
|
||||
// xs 0 xc(1-xs)
|
||||
// 0 ys yc(1-ys)
|
||||
// 0 0 1
|
||||
//
|
||||
wxTransformMatrix& wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc)
|
||||
{
|
||||
double r00,r10,r20,r01,r11,r21;
|
||||
|
||||
if (m_isIdentity)
|
||||
{
|
||||
double tx = xc*(1-xs);
|
||||
double ty = yc*(1-ys);
|
||||
r00 = xs;
|
||||
r10 = 0;
|
||||
r20 = tx;
|
||||
r01 = 0;
|
||||
r11 = ys;
|
||||
r21 = ty;
|
||||
}
|
||||
else if ( !wxIsNullDouble(xc) || !wxIsNullDouble(yc) )
|
||||
{
|
||||
double tx = xc*(1-xs);
|
||||
double ty = yc*(1-ys);
|
||||
r00 = xs * m_matrix[0][0];
|
||||
r10 = xs * m_matrix[1][0];
|
||||
r20 = xs * m_matrix[2][0] + tx;
|
||||
r01 = ys * m_matrix[0][1];
|
||||
r11 = ys * m_matrix[1][1];
|
||||
r21 = ys * m_matrix[2][1] + ty;
|
||||
}
|
||||
else
|
||||
{
|
||||
r00 = xs * m_matrix[0][0];
|
||||
r10 = xs * m_matrix[1][0];
|
||||
r20 = xs * m_matrix[2][0];
|
||||
r01 = ys * m_matrix[0][1];
|
||||
r11 = ys * m_matrix[1][1];
|
||||
r21 = ys * m_matrix[2][1];
|
||||
}
|
||||
|
||||
m_matrix[0][0] = r00;
|
||||
m_matrix[1][0] = r10;
|
||||
m_matrix[2][0] = r20;
|
||||
m_matrix[0][1] = r01;
|
||||
m_matrix[1][1] = r11;
|
||||
m_matrix[2][1] = r21;
|
||||
|
||||
/* or like this
|
||||
// first translate to origin O
|
||||
(*this).Translate(-x_cen, -y_cen);
|
||||
|
||||
// now do the scaling
|
||||
wxTransformMatrix scale;
|
||||
scale.m_matrix[0][0] = x_fac;
|
||||
scale.m_matrix[1][1] = y_fac;
|
||||
scale.m_isIdentity = IsIdentity1();
|
||||
|
||||
*this = scale * (*this);
|
||||
|
||||
// translate back from origin to x_cen, y_cen
|
||||
(*this).Translate(x_cen, y_cen);
|
||||
*/
|
||||
|
||||
m_isIdentity = IsIdentity1();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// mirror a matrix in x, y
|
||||
//
|
||||
// -1 0 0 Y-mirror
|
||||
// 0 -1 0 X-mirror
|
||||
// 0 0 -1 Z-mirror
|
||||
wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y)
|
||||
{
|
||||
wxTransformMatrix temp;
|
||||
if (x)
|
||||
{
|
||||
temp.m_matrix[1][1] = -1;
|
||||
temp.m_isIdentity=false;
|
||||
}
|
||||
if (y)
|
||||
{
|
||||
temp.m_matrix[0][0] = -1;
|
||||
temp.m_isIdentity=false;
|
||||
}
|
||||
|
||||
*this = temp * (*this);
|
||||
m_isIdentity = IsIdentity1();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Translate by dx, dy:
|
||||
// | 1 0 dx |
|
||||
// matrix' = | 0 1 dy | x matrix
|
||||
// | 0 0 1 |
|
||||
//
|
||||
bool wxTransformMatrix::Translate(double dx, double dy)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 3; i++)
|
||||
m_matrix[i][0] += dx * m_matrix[i][2];
|
||||
for (i = 0; i < 3; i++)
|
||||
m_matrix[i][1] += dy * m_matrix[i][2];
|
||||
|
||||
m_isIdentity = IsIdentity1();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Rotate clockwise by the given number of degrees:
|
||||
// | cos sin 0 |
|
||||
// matrix' = | -sin cos 0 | x matrix
|
||||
// | 0 0 1 |
|
||||
bool wxTransformMatrix::Rotate(double degrees)
|
||||
{
|
||||
Rotate(-degrees,0,0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// counter clockwise rotate around a point
|
||||
//
|
||||
// cos(r) -sin(r) x(1-cos(r))+y(sin(r)
|
||||
// sin(r) cos(r) y(1-cos(r))-x(sin(r)
|
||||
// 0 0 1
|
||||
wxTransformMatrix& wxTransformMatrix::Rotate(const double °rees, const double &x, const double &y)
|
||||
{
|
||||
double angle = degrees * pi / 180.0;
|
||||
double c = cos(angle);
|
||||
double s = sin(angle);
|
||||
double r00,r10,r20,r01,r11,r21;
|
||||
|
||||
if (m_isIdentity)
|
||||
{
|
||||
double tx = x*(1-c)+y*s;
|
||||
double ty = y*(1-c)-x*s;
|
||||
r00 = c ;
|
||||
r10 = -s;
|
||||
r20 = tx;
|
||||
r01 = s;
|
||||
r11 = c;
|
||||
r21 = ty;
|
||||
}
|
||||
else if ( !wxIsNullDouble(x) || !wxIsNullDouble(y) )
|
||||
{
|
||||
double tx = x*(1-c)+y*s;
|
||||
double ty = y*(1-c)-x*s;
|
||||
r00 = c * m_matrix[0][0] - s * m_matrix[0][1] + tx * m_matrix[0][2];
|
||||
r10 = c * m_matrix[1][0] - s * m_matrix[1][1] + tx * m_matrix[1][2];
|
||||
r20 = c * m_matrix[2][0] - s * m_matrix[2][1] + tx;// * m_matrix[2][2];
|
||||
r01 = c * m_matrix[0][1] + s * m_matrix[0][0] + ty * m_matrix[0][2];
|
||||
r11 = c * m_matrix[1][1] + s * m_matrix[1][0] + ty * m_matrix[1][2];
|
||||
r21 = c * m_matrix[2][1] + s * m_matrix[2][0] + ty;// * m_matrix[2][2];
|
||||
}
|
||||
else
|
||||
{
|
||||
r00 = c * m_matrix[0][0] - s * m_matrix[0][1];
|
||||
r10 = c * m_matrix[1][0] - s * m_matrix[1][1];
|
||||
r20 = c * m_matrix[2][0] - s * m_matrix[2][1];
|
||||
r01 = c * m_matrix[0][1] + s * m_matrix[0][0];
|
||||
r11 = c * m_matrix[1][1] + s * m_matrix[1][0];
|
||||
r21 = c * m_matrix[2][1] + s * m_matrix[2][0];
|
||||
}
|
||||
|
||||
m_matrix[0][0] = r00;
|
||||
m_matrix[1][0] = r10;
|
||||
m_matrix[2][0] = r20;
|
||||
m_matrix[0][1] = r01;
|
||||
m_matrix[1][1] = r11;
|
||||
m_matrix[2][1] = r21;
|
||||
|
||||
/* or like this
|
||||
wxTransformMatrix rotate;
|
||||
rotate.m_matrix[2][0] = tx;
|
||||
rotate.m_matrix[2][1] = ty;
|
||||
|
||||
rotate.m_matrix[0][0] = c;
|
||||
rotate.m_matrix[0][1] = s;
|
||||
|
||||
rotate.m_matrix[1][0] = -s;
|
||||
rotate.m_matrix[1][1] = c;
|
||||
|
||||
rotate.m_isIdentity=false;
|
||||
*this = rotate * (*this);
|
||||
*/
|
||||
m_isIdentity = IsIdentity1();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Transform a point from logical to device coordinates
|
||||
bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const
|
||||
{
|
||||
if (IsIdentity())
|
||||
{
|
||||
tx = x; ty = y; return true;
|
||||
}
|
||||
|
||||
tx = x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0];
|
||||
ty = x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Transform a point from device to logical coordinates.
|
||||
|
||||
// Example of use:
|
||||
// wxTransformMatrix mat = dc.GetTransformation();
|
||||
// mat.Invert();
|
||||
// mat.InverseTransformPoint(x, y, x1, y1);
|
||||
// OR (shorthand:)
|
||||
// dc.LogicalToDevice(x, y, x1, y1);
|
||||
// The latter is slightly less efficient if we're doing several
|
||||
// conversions, since the matrix is inverted several times.
|
||||
bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const
|
||||
{
|
||||
if (IsIdentity())
|
||||
{
|
||||
tx = x;
|
||||
ty = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
const double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2];
|
||||
if ( wxIsNullDouble(z) )
|
||||
return false;
|
||||
|
||||
tx = x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0];
|
||||
ty = x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1];
|
||||
return true;
|
||||
}
|
||||
|
||||
wxTransformMatrix& wxTransformMatrix::operator*=(const double& t)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 3; j++)
|
||||
m_matrix[i][j]*= t;
|
||||
m_isIdentity = IsIdentity1();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxTransformMatrix& wxTransformMatrix::operator/=(const double& t)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 3; j++)
|
||||
m_matrix[i][j]/= t;
|
||||
m_isIdentity = IsIdentity1();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxTransformMatrix& wxTransformMatrix::operator+=(const wxTransformMatrix& mat)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 3; j++)
|
||||
m_matrix[i][j] += mat.m_matrix[i][j];
|
||||
m_isIdentity = IsIdentity1();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 3; j++)
|
||||
m_matrix[i][j] -= mat.m_matrix[i][j];
|
||||
m_isIdentity = IsIdentity1();
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat)
|
||||
{
|
||||
|
||||
if (mat.m_isIdentity)
|
||||
return *this;
|
||||
if (m_isIdentity)
|
||||
{
|
||||
*this = mat;
|
||||
return *this;
|
||||
}
|
||||
else
|
||||
{
|
||||
wxTransformMatrix result;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
double sum = 0;
|
||||
for (int k = 0; k < 3; k++)
|
||||
sum += m_matrix[k][i] * mat.m_matrix[j][k];
|
||||
result.m_matrix[j][i] = sum;
|
||||
}
|
||||
}
|
||||
*this = result;
|
||||
}
|
||||
|
||||
m_isIdentity = IsIdentity1();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// constant operators
|
||||
wxTransformMatrix wxTransformMatrix::operator*(const double& t) const
|
||||
{
|
||||
wxTransformMatrix result = *this;
|
||||
result *= t;
|
||||
result.m_isIdentity = result.IsIdentity1();
|
||||
return result;
|
||||
}
|
||||
|
||||
wxTransformMatrix wxTransformMatrix::operator/(const double& t) const
|
||||
{
|
||||
wxTransformMatrix result = *this;
|
||||
// wxASSERT(t!=0);
|
||||
result /= t;
|
||||
result.m_isIdentity = result.IsIdentity1();
|
||||
return result;
|
||||
}
|
||||
|
||||
wxTransformMatrix wxTransformMatrix::operator+(const wxTransformMatrix& m) const
|
||||
{
|
||||
wxTransformMatrix result = *this;
|
||||
result += m;
|
||||
result.m_isIdentity = result.IsIdentity1();
|
||||
return result;
|
||||
}
|
||||
|
||||
wxTransformMatrix wxTransformMatrix::operator-(const wxTransformMatrix& m) const
|
||||
{
|
||||
wxTransformMatrix result = *this;
|
||||
result -= m;
|
||||
result.m_isIdentity = result.IsIdentity1();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
wxTransformMatrix wxTransformMatrix::operator*(const wxTransformMatrix& m) const
|
||||
{
|
||||
wxTransformMatrix result = *this;
|
||||
result *= m;
|
||||
result.m_isIdentity = result.IsIdentity1();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
wxTransformMatrix wxTransformMatrix::operator-() const
|
||||
{
|
||||
wxTransformMatrix result = *this;
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 3; j++)
|
||||
result.m_matrix[i][j] = -(this->m_matrix[i][j]);
|
||||
result.m_isIdentity = result.IsIdentity1();
|
||||
return result;
|
||||
}
|
||||
|
||||
static double CheckInt(double getal)
|
||||
{
|
||||
// check if the number is very close to an integer
|
||||
if ( (ceil(getal) - getal) < 0.0001)
|
||||
return ceil(getal);
|
||||
|
||||
else if ( (getal - floor(getal)) < 0.0001)
|
||||
return floor(getal);
|
||||
|
||||
return getal;
|
||||
|
||||
}
|
||||
|
||||
double wxTransformMatrix::Get_scaleX()
|
||||
{
|
||||
double scale_factor;
|
||||
double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi);
|
||||
if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) )
|
||||
scale_factor = m_matrix[0][0]/cos((rot_angle/180)*pi);
|
||||
else
|
||||
scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden !
|
||||
|
||||
scale_factor = CheckInt(scale_factor);
|
||||
if (scale_factor < 0)
|
||||
scale_factor = -scale_factor;
|
||||
|
||||
return scale_factor;
|
||||
}
|
||||
|
||||
double wxTransformMatrix::Get_scaleY()
|
||||
{
|
||||
double scale_factor;
|
||||
double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi);
|
||||
if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) )
|
||||
scale_factor = m_matrix[1][1]/cos((rot_angle/180)*pi);
|
||||
else
|
||||
scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden !
|
||||
|
||||
scale_factor = CheckInt(scale_factor);
|
||||
if (scale_factor < 0)
|
||||
|
||||
scale_factor = -scale_factor;
|
||||
|
||||
return scale_factor;
|
||||
|
||||
}
|
||||
|
||||
double wxTransformMatrix::GetRotation()
|
||||
{
|
||||
double temp1 = GetValue(0,0); // for angle calculation
|
||||
double temp2 = GetValue(0,1); //
|
||||
|
||||
// Rotation
|
||||
double rot_angle = atan2(temp2,temp1)*180/pi;
|
||||
|
||||
rot_angle = CheckInt(rot_angle);
|
||||
return rot_angle;
|
||||
}
|
||||
|
||||
void wxTransformMatrix::SetRotation(double rotation)
|
||||
{
|
||||
double x=GetValue(2,0);
|
||||
double y=GetValue(2,1);
|
||||
Rotate(-GetRotation(), x, y);
|
||||
Rotate(rotation, x, y);
|
||||
}
|
||||
|
||||
#endif // WXWIN_COMPATIBILITY_3_0
|
||||
@@ -0,0 +1,757 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/mimecmn.cpp
|
||||
// Purpose: classes and functions to manage MIME types
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Chris Elliott (biol75@york.ac.uk) 5 Dec 00: write support for Win32
|
||||
// Created: 23.09.98
|
||||
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
|
||||
// Licence: wxWindows licence (part of wxExtra library)
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_MIMETYPE
|
||||
|
||||
#include "wx/mimetype.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/dynarray.h"
|
||||
#include "wx/string.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/module.h"
|
||||
#include "wx/crt.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include "wx/file.h"
|
||||
#include "wx/iconloc.h"
|
||||
#include "wx/confbase.h"
|
||||
|
||||
// other standard headers
|
||||
#include <ctype.h>
|
||||
|
||||
// implementation classes:
|
||||
#if defined(__WINDOWS__)
|
||||
#include "wx/msw/mimetype.h"
|
||||
#elif ( defined(__DARWIN__) )
|
||||
#include "wx/osx/mimetype.h"
|
||||
#else // Unix
|
||||
#include "wx/unix/mimetype.h"
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// common classes
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMimeTypeCommands
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
wxMimeTypeCommands::AddOrReplaceVerb(const wxString& verb, const wxString& cmd)
|
||||
{
|
||||
int n = m_verbs.Index(verb, false /* ignore case */);
|
||||
if ( n == wxNOT_FOUND )
|
||||
{
|
||||
m_verbs.Add(verb);
|
||||
m_commands.Add(cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_commands[n] = cmd;
|
||||
}
|
||||
}
|
||||
|
||||
wxString
|
||||
wxMimeTypeCommands::GetCommandForVerb(const wxString& verb, size_t *idx) const
|
||||
{
|
||||
wxString s;
|
||||
|
||||
int n = m_verbs.Index(verb);
|
||||
if ( n != wxNOT_FOUND )
|
||||
{
|
||||
s = m_commands[(size_t)n];
|
||||
if ( idx )
|
||||
*idx = n;
|
||||
}
|
||||
else if ( idx )
|
||||
{
|
||||
// different from any valid index
|
||||
*idx = (size_t)-1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
wxString wxMimeTypeCommands::GetVerbCmd(size_t n) const
|
||||
{
|
||||
return m_verbs[n] + wxT('=') + m_commands[n];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFileTypeInfo
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxFileTypeInfo::DoVarArgInit(const wxString& mimeType,
|
||||
const wxString& openCmd,
|
||||
const wxString& printCmd,
|
||||
const wxString& desc,
|
||||
va_list argptr)
|
||||
{
|
||||
m_mimeType = mimeType;
|
||||
m_openCmd = openCmd;
|
||||
m_printCmd = printCmd;
|
||||
m_desc = desc;
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
// icc gives this warning in its own va_arg() macro, argh
|
||||
#ifdef __INTELC__
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 1684)
|
||||
#endif
|
||||
|
||||
wxArgNormalizedString ext(WX_VA_ARG_STRING(argptr));
|
||||
|
||||
#ifdef __INTELC__
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
if ( !ext )
|
||||
{
|
||||
// NULL terminates the list
|
||||
break;
|
||||
}
|
||||
|
||||
m_exts.Add(ext.GetString());
|
||||
}
|
||||
}
|
||||
|
||||
void wxFileTypeInfo::VarArgInit(const wxString *mimeType,
|
||||
const wxString *openCmd,
|
||||
const wxString *printCmd,
|
||||
const wxString *desc,
|
||||
...)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, desc);
|
||||
|
||||
DoVarArgInit(*mimeType, *openCmd, *printCmd, *desc, argptr);
|
||||
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
|
||||
wxFileTypeInfo::wxFileTypeInfo(const wxArrayString& sArray)
|
||||
: m_mimeType(sArray[0u])
|
||||
, m_openCmd( sArray[1u])
|
||||
, m_printCmd(sArray[2u])
|
||||
, m_desc( sArray[3u])
|
||||
{
|
||||
size_t count = sArray.GetCount();
|
||||
for ( size_t i = 4; i < count; i++ )
|
||||
{
|
||||
m_exts.Add(sArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#include "wx/arrimpl.cpp"
|
||||
WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo)
|
||||
|
||||
// ============================================================================
|
||||
// implementation of the wrapper classes
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFileType
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/* static */
|
||||
wxString wxFileType::ExpandCommand(const wxString& command,
|
||||
const wxFileType::MessageParameters& params)
|
||||
{
|
||||
bool hasFilename = false;
|
||||
|
||||
// We consider that only the file names with spaces in them need to be
|
||||
// handled specially. This is not perfect, but this can be done easily
|
||||
// under all platforms while handling the file names with quotes in them,
|
||||
// for example, needs to be done differently.
|
||||
const bool needToQuoteFilename = params.GetFileName().find_first_of(" \t")
|
||||
!= wxString::npos;
|
||||
|
||||
wxString str;
|
||||
for ( const wxChar *pc = command.c_str(); *pc != wxT('\0'); pc++ ) {
|
||||
if ( *pc == wxT('%') ) {
|
||||
switch ( *++pc ) {
|
||||
case wxT('s'):
|
||||
// don't quote the file name if it's already quoted: notice
|
||||
// that we check for a quote following it and not preceding
|
||||
// it as at least under Windows we can have commands
|
||||
// containing "file://%s" (with quotes) in them so the
|
||||
// argument may be quoted even if there is no quote
|
||||
// directly before "%s" itself
|
||||
if ( needToQuoteFilename && pc[1] != '"' )
|
||||
str << wxT('"') << params.GetFileName() << wxT('"');
|
||||
else
|
||||
str << params.GetFileName();
|
||||
hasFilename = true;
|
||||
break;
|
||||
|
||||
case wxT('t'):
|
||||
// '%t' expands into MIME type (quote it too just to be
|
||||
// consistent)
|
||||
str << wxT('\'') << params.GetMimeType() << wxT('\'');
|
||||
break;
|
||||
|
||||
case wxT('{'):
|
||||
{
|
||||
const wxChar *pEnd = wxStrchr(pc, wxT('}'));
|
||||
if ( pEnd == NULL ) {
|
||||
wxString mimetype;
|
||||
wxLogWarning(_("Unmatched '{' in an entry for mime type %s."),
|
||||
params.GetMimeType().c_str());
|
||||
str << wxT("%{");
|
||||
}
|
||||
else {
|
||||
wxString param(pc + 1, pEnd - pc - 1);
|
||||
str << wxT('\'') << params.GetParamValue(param) << wxT('\'');
|
||||
pc = pEnd;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case wxT('n'):
|
||||
case wxT('F'):
|
||||
// TODO %n is the number of parts, %F is an array containing
|
||||
// the names of temp files these parts were written to
|
||||
// and their mime types.
|
||||
break;
|
||||
|
||||
default:
|
||||
wxLogDebug(wxT("Unknown field %%%c in command '%s'."),
|
||||
*pc, command.c_str());
|
||||
str << *pc;
|
||||
}
|
||||
}
|
||||
else {
|
||||
str << *pc;
|
||||
}
|
||||
}
|
||||
|
||||
// metamail(1) man page states that if the mailcap entry doesn't have '%s'
|
||||
// the program will accept the data on stdin so normally we should append
|
||||
// "< %s" to the end of the command in such case, but not all commands
|
||||
// behave like this, in particular a common test is 'test -n "$DISPLAY"'
|
||||
// and appending "< %s" to this command makes the test fail... I don't
|
||||
// know of the correct solution, try to guess what we have to do.
|
||||
|
||||
// test now carried out on reading file so test should never get here
|
||||
if ( !hasFilename && !str.empty()
|
||||
#ifdef __UNIX__
|
||||
&& !str.StartsWith(wxT("test "))
|
||||
#endif // Unix
|
||||
)
|
||||
{
|
||||
str << wxT(" < ");
|
||||
if ( needToQuoteFilename )
|
||||
str << '"';
|
||||
str << params.GetFileName();
|
||||
if ( needToQuoteFilename )
|
||||
str << '"';
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
wxFileType::wxFileType(const wxFileTypeInfo& info)
|
||||
{
|
||||
m_info = &info;
|
||||
m_impl = NULL;
|
||||
}
|
||||
|
||||
wxFileType::wxFileType()
|
||||
{
|
||||
m_info = NULL;
|
||||
m_impl = new wxFileTypeImpl;
|
||||
}
|
||||
|
||||
wxFileType::~wxFileType()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
bool wxFileType::GetExtensions(wxArrayString& extensions)
|
||||
{
|
||||
if ( m_info )
|
||||
{
|
||||
extensions = m_info->GetExtensions();
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_impl->GetExtensions(extensions);
|
||||
}
|
||||
|
||||
bool wxFileType::GetMimeType(wxString *mimeType) const
|
||||
{
|
||||
wxCHECK_MSG( mimeType, false, wxT("invalid parameter in GetMimeType") );
|
||||
|
||||
if ( m_info )
|
||||
{
|
||||
*mimeType = m_info->GetMimeType();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_impl->GetMimeType(mimeType);
|
||||
}
|
||||
|
||||
bool wxFileType::GetMimeTypes(wxArrayString& mimeTypes) const
|
||||
{
|
||||
if ( m_info )
|
||||
{
|
||||
mimeTypes.Clear();
|
||||
mimeTypes.Add(m_info->GetMimeType());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_impl->GetMimeTypes(mimeTypes);
|
||||
}
|
||||
|
||||
bool wxFileType::GetIcon(wxIconLocation *iconLoc) const
|
||||
{
|
||||
if ( m_info )
|
||||
{
|
||||
if ( iconLoc )
|
||||
{
|
||||
iconLoc->SetFileName(m_info->GetIconFile());
|
||||
#ifdef __WINDOWS__
|
||||
iconLoc->SetIndex(m_info->GetIconIndex());
|
||||
#endif // __WINDOWS__
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_impl->GetIcon(iconLoc);
|
||||
}
|
||||
|
||||
bool
|
||||
wxFileType::GetIcon(wxIconLocation *iconloc,
|
||||
const MessageParameters& params) const
|
||||
{
|
||||
if ( !GetIcon(iconloc) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// we may have "%s" in the icon location string, at least under Windows, so
|
||||
// expand this
|
||||
if ( iconloc )
|
||||
{
|
||||
iconloc->SetFileName(ExpandCommand(iconloc->GetFileName(), params));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxFileType::GetDescription(wxString *desc) const
|
||||
{
|
||||
wxCHECK_MSG( desc, false, wxT("invalid parameter in GetDescription") );
|
||||
|
||||
if ( m_info )
|
||||
{
|
||||
*desc = m_info->GetDescription();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_impl->GetDescription(desc);
|
||||
}
|
||||
|
||||
bool
|
||||
wxFileType::GetOpenCommand(wxString *openCmd,
|
||||
const wxFileType::MessageParameters& params) const
|
||||
{
|
||||
wxCHECK_MSG( openCmd, false, wxT("invalid parameter in GetOpenCommand") );
|
||||
|
||||
if ( m_info )
|
||||
{
|
||||
*openCmd = ExpandCommand(m_info->GetOpenCommand(), params);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_impl->GetOpenCommand(openCmd, params);
|
||||
}
|
||||
|
||||
wxString wxFileType::GetOpenCommand(const wxString& filename) const
|
||||
{
|
||||
wxString cmd;
|
||||
if ( !GetOpenCommand(&cmd, filename) )
|
||||
{
|
||||
// return empty string to indicate an error
|
||||
cmd.clear();
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
bool
|
||||
wxFileType::GetPrintCommand(wxString *printCmd,
|
||||
const wxFileType::MessageParameters& params) const
|
||||
{
|
||||
wxCHECK_MSG( printCmd, false, wxT("invalid parameter in GetPrintCommand") );
|
||||
|
||||
if ( m_info )
|
||||
{
|
||||
*printCmd = ExpandCommand(m_info->GetPrintCommand(), params);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_impl->GetPrintCommand(printCmd, params);
|
||||
}
|
||||
|
||||
wxString
|
||||
wxFileType::GetExpandedCommand(const wxString& verb,
|
||||
const wxFileType::MessageParameters& params) const
|
||||
{
|
||||
return m_impl->GetExpandedCommand(verb, params);
|
||||
}
|
||||
|
||||
|
||||
size_t wxFileType::GetAllCommands(wxArrayString *verbs,
|
||||
wxArrayString *commands,
|
||||
const wxFileType::MessageParameters& params) const
|
||||
{
|
||||
if ( verbs )
|
||||
verbs->Clear();
|
||||
if ( commands )
|
||||
commands->Clear();
|
||||
|
||||
#if defined (__WINDOWS__) || defined(__UNIX__)
|
||||
return m_impl->GetAllCommands(verbs, commands, params);
|
||||
#else // !__WINDOWS__ || __UNIX__
|
||||
// we don't know how to retrieve all commands, so just try the 2 we know
|
||||
// about
|
||||
size_t count = 0;
|
||||
wxString cmd;
|
||||
if ( GetOpenCommand(&cmd, params) )
|
||||
{
|
||||
if ( verbs )
|
||||
verbs->Add(wxT("Open"));
|
||||
if ( commands )
|
||||
commands->Add(cmd);
|
||||
count++;
|
||||
}
|
||||
|
||||
if ( GetPrintCommand(&cmd, params) )
|
||||
{
|
||||
if ( verbs )
|
||||
verbs->Add(wxT("Print"));
|
||||
if ( commands )
|
||||
commands->Add(cmd);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
#endif // __WINDOWS__/| __UNIX__
|
||||
}
|
||||
|
||||
bool wxFileType::Unassociate()
|
||||
{
|
||||
#if defined(__WINDOWS__)
|
||||
return m_impl->Unassociate();
|
||||
#elif defined(__UNIX__)
|
||||
return m_impl->Unassociate(this);
|
||||
#else
|
||||
wxFAIL_MSG( wxT("not implemented") ); // TODO
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool wxFileType::SetCommand(const wxString& cmd,
|
||||
const wxString& verb,
|
||||
bool overwriteprompt)
|
||||
{
|
||||
#if defined (__WINDOWS__) || defined(__UNIX__)
|
||||
return m_impl->SetCommand(cmd, verb, overwriteprompt);
|
||||
#else
|
||||
wxUnusedVar(cmd);
|
||||
wxUnusedVar(verb);
|
||||
wxUnusedVar(overwriteprompt);
|
||||
wxFAIL_MSG(wxT("not implemented"));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool wxFileType::SetDefaultIcon(const wxString& cmd, int index)
|
||||
{
|
||||
wxString sTmp = cmd;
|
||||
#ifdef __WINDOWS__
|
||||
// VZ: should we do this?
|
||||
// chris elliott : only makes sense in MS windows
|
||||
if ( sTmp.empty() )
|
||||
GetOpenCommand(&sTmp, wxFileType::MessageParameters(wxEmptyString, wxEmptyString));
|
||||
#endif
|
||||
wxCHECK_MSG( !sTmp.empty(), false, wxT("need the icon file") );
|
||||
|
||||
#if defined (__WINDOWS__) || defined(__UNIX__)
|
||||
return m_impl->SetDefaultIcon (cmd, index);
|
||||
#else
|
||||
wxUnusedVar(index);
|
||||
wxFAIL_MSG(wxT("not implemented"));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMimeTypesManagerFactory
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::m_factory = NULL;
|
||||
|
||||
/* static */
|
||||
void wxMimeTypesManagerFactory::Set(wxMimeTypesManagerFactory *factory)
|
||||
{
|
||||
delete m_factory;
|
||||
|
||||
m_factory = factory;
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::Get()
|
||||
{
|
||||
if ( !m_factory )
|
||||
m_factory = new wxMimeTypesManagerFactory;
|
||||
|
||||
return m_factory;
|
||||
}
|
||||
|
||||
wxMimeTypesManagerImpl *wxMimeTypesManagerFactory::CreateMimeTypesManagerImpl()
|
||||
{
|
||||
return new wxMimeTypesManagerImpl;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMimeTypesManager
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxMimeTypesManager::EnsureImpl()
|
||||
{
|
||||
if ( !m_impl )
|
||||
m_impl = wxMimeTypesManagerFactory::Get()->CreateMimeTypesManagerImpl();
|
||||
}
|
||||
|
||||
bool wxMimeTypesManager::IsOfType(const wxString& mimeType,
|
||||
const wxString& wildcard)
|
||||
{
|
||||
wxASSERT_MSG( mimeType.Find(wxT('*')) == wxNOT_FOUND,
|
||||
wxT("first MIME type can't contain wildcards") );
|
||||
|
||||
// all comparaisons are case insensitive (2nd arg of IsSameAs() is false)
|
||||
if ( wildcard.BeforeFirst(wxT('/')).
|
||||
IsSameAs(mimeType.BeforeFirst(wxT('/')), false) )
|
||||
{
|
||||
wxString strSubtype = wildcard.AfterFirst(wxT('/'));
|
||||
|
||||
if ( strSubtype == wxT("*") ||
|
||||
strSubtype.IsSameAs(mimeType.AfterFirst(wxT('/')), false) )
|
||||
{
|
||||
// matches (either exactly or it's a wildcard)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxMimeTypesManager::wxMimeTypesManager()
|
||||
{
|
||||
m_impl = NULL;
|
||||
}
|
||||
|
||||
wxMimeTypesManager::~wxMimeTypesManager()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
bool wxMimeTypesManager::Unassociate(wxFileType *ft)
|
||||
{
|
||||
EnsureImpl();
|
||||
|
||||
#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
|
||||
return m_impl->Unassociate(ft);
|
||||
#else
|
||||
return ft->Unassociate();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
wxFileType *
|
||||
wxMimeTypesManager::Associate(const wxFileTypeInfo& ftInfo)
|
||||
{
|
||||
EnsureImpl();
|
||||
|
||||
#if defined(__WINDOWS__) || defined(__UNIX__)
|
||||
return m_impl->Associate(ftInfo);
|
||||
#else // other platforms
|
||||
wxUnusedVar(ftInfo);
|
||||
wxFAIL_MSG( wxT("not implemented") ); // TODO
|
||||
return NULL;
|
||||
#endif // platforms
|
||||
}
|
||||
|
||||
wxFileType *
|
||||
wxMimeTypesManager::GetFileTypeFromExtension(const wxString& ext)
|
||||
{
|
||||
EnsureImpl();
|
||||
|
||||
wxString::const_iterator i = ext.begin();
|
||||
const wxString::const_iterator end = ext.end();
|
||||
wxString extWithoutDot;
|
||||
if ( i != end && *i == '.' )
|
||||
extWithoutDot.assign(++i, ext.end());
|
||||
else
|
||||
extWithoutDot = ext;
|
||||
|
||||
wxCHECK_MSG( !ext.empty(), NULL, wxT("extension can't be empty") );
|
||||
|
||||
wxFileType *ft = m_impl->GetFileTypeFromExtension(extWithoutDot);
|
||||
|
||||
if ( !ft ) {
|
||||
// check the fallbacks
|
||||
//
|
||||
// TODO linear search is potentially slow, perhaps we should use a
|
||||
// sorted array?
|
||||
size_t count = m_fallbacks.GetCount();
|
||||
for ( size_t n = 0; n < count; n++ ) {
|
||||
if ( m_fallbacks[n].GetExtensions().Index(ext) != wxNOT_FOUND ) {
|
||||
ft = new wxFileType(m_fallbacks[n]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ft;
|
||||
}
|
||||
|
||||
wxFileType *
|
||||
wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType)
|
||||
{
|
||||
EnsureImpl();
|
||||
wxFileType *ft = m_impl->GetFileTypeFromMimeType(mimeType);
|
||||
|
||||
if ( !ft ) {
|
||||
// check the fallbacks
|
||||
//
|
||||
// TODO linear search is potentially slow, perhaps we should use a
|
||||
// sorted array?
|
||||
size_t count = m_fallbacks.GetCount();
|
||||
for ( size_t n = 0; n < count; n++ ) {
|
||||
if ( wxMimeTypesManager::IsOfType(mimeType,
|
||||
m_fallbacks[n].GetMimeType()) ) {
|
||||
ft = new wxFileType(m_fallbacks[n]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ft;
|
||||
}
|
||||
|
||||
void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo *filetypes)
|
||||
{
|
||||
EnsureImpl();
|
||||
for ( const wxFileTypeInfo *ft = filetypes; ft && ft->IsValid(); ft++ ) {
|
||||
AddFallback(*ft);
|
||||
}
|
||||
}
|
||||
|
||||
size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString& mimetypes)
|
||||
{
|
||||
EnsureImpl();
|
||||
size_t countAll = m_impl->EnumAllFileTypes(mimetypes);
|
||||
|
||||
// add the fallback filetypes
|
||||
size_t count = m_fallbacks.GetCount();
|
||||
for ( size_t n = 0; n < count; n++ ) {
|
||||
if ( mimetypes.Index(m_fallbacks[n].GetMimeType()) == wxNOT_FOUND ) {
|
||||
mimetypes.Add(m_fallbacks[n].GetMimeType());
|
||||
countAll++;
|
||||
}
|
||||
}
|
||||
|
||||
return countAll;
|
||||
}
|
||||
|
||||
void wxMimeTypesManager::Initialize(int mcapStyle,
|
||||
const wxString& sExtraDir)
|
||||
{
|
||||
#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
|
||||
EnsureImpl();
|
||||
|
||||
m_impl->Initialize(mcapStyle, sExtraDir);
|
||||
#else
|
||||
(void)mcapStyle;
|
||||
(void)sExtraDir;
|
||||
#endif // Unix
|
||||
}
|
||||
|
||||
// and this function clears all the data from the manager
|
||||
void wxMimeTypesManager::ClearData()
|
||||
{
|
||||
#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
|
||||
EnsureImpl();
|
||||
|
||||
m_impl->ClearData();
|
||||
#endif // Unix
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// global data and wxMimeTypeCmnModule
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// private object
|
||||
static wxMimeTypesManager gs_mimeTypesManager;
|
||||
|
||||
// and public pointer
|
||||
wxMimeTypesManager *wxTheMimeTypesManager = &gs_mimeTypesManager;
|
||||
|
||||
class wxMimeTypeCmnModule: public wxModule
|
||||
{
|
||||
public:
|
||||
wxMimeTypeCmnModule() : wxModule() { }
|
||||
|
||||
virtual bool OnInit() wxOVERRIDE { return true; }
|
||||
virtual void OnExit() wxOVERRIDE
|
||||
{
|
||||
wxMimeTypesManagerFactory::Set(NULL);
|
||||
|
||||
if ( gs_mimeTypesManager.m_impl != NULL )
|
||||
{
|
||||
wxDELETE(gs_mimeTypesManager.m_impl);
|
||||
gs_mimeTypesManager.m_fallbacks.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
wxDECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule);
|
||||
};
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule, wxModule);
|
||||
|
||||
#endif // wxUSE_MIMETYPE
|
||||
@@ -0,0 +1,116 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/modalhook.cpp
|
||||
// Purpose: wxModalDialogHook implementation
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2013-05-19
|
||||
// Copyright: (c) 2013 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/modalhook.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
wxModalDialogHook::Hooks wxModalDialogHook::ms_hooks;
|
||||
|
||||
// ============================================================================
|
||||
// wxModalDialogHook implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Hooks management
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxModalDialogHook::Register()
|
||||
{
|
||||
#if wxDEBUG_LEVEL
|
||||
for ( Hooks::const_iterator it = ms_hooks.begin();
|
||||
it != ms_hooks.end();
|
||||
++it)
|
||||
{
|
||||
if ( *it == this )
|
||||
{
|
||||
wxFAIL_MSG( wxS("Registering already registered hook?") );
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // wxDEBUG_LEVEL
|
||||
|
||||
ms_hooks.insert(ms_hooks.begin(), this);
|
||||
}
|
||||
|
||||
void wxModalDialogHook::Unregister()
|
||||
{
|
||||
if ( !DoUnregister() )
|
||||
{
|
||||
wxFAIL_MSG( wxS("Unregistering not registered hook?") );
|
||||
}
|
||||
}
|
||||
|
||||
bool wxModalDialogHook::DoUnregister()
|
||||
{
|
||||
for ( Hooks::iterator it = ms_hooks.begin();
|
||||
it != ms_hooks.end();
|
||||
++it )
|
||||
{
|
||||
if ( *it == this )
|
||||
{
|
||||
ms_hooks.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Invoking hooks methods
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/* static */
|
||||
int wxModalDialogHook::CallEnter(wxDialog* dialog)
|
||||
{
|
||||
// Make a copy of the hooks list to avoid problems if it's modified while
|
||||
// we're iterating over it: this is unlikely to happen in our case, but
|
||||
// quite possible in CallExit() as the hooks may remove themselves after
|
||||
// the call to their Exit(), so do it here for symmetry as well.
|
||||
const Hooks hooks = ms_hooks;
|
||||
|
||||
for ( Hooks::const_iterator it = hooks.begin(); it != hooks.end(); ++it )
|
||||
{
|
||||
const int rc = (*it)->Enter(dialog);
|
||||
if ( rc != wxID_NONE )
|
||||
{
|
||||
// Skip calling all the rest of the hooks if one of them preempts
|
||||
// showing the dialog completely.
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return wxID_NONE;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void wxModalDialogHook::CallExit(wxDialog* dialog)
|
||||
{
|
||||
// See comment in CallEnter() for the reasons for making a copy here.
|
||||
const Hooks hooks = ms_hooks;
|
||||
|
||||
for ( Hooks::const_iterator it = hooks.begin(); it != hooks.end(); ++it )
|
||||
{
|
||||
(*it)->Exit(dialog);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/module.cpp
|
||||
// Purpose: Modules initialization/destruction
|
||||
// Author: Wolfram Gloger/adapted by Guilhem Lavaux
|
||||
// Modified by:
|
||||
// Created: 04/11/98
|
||||
// Copyright: (c) Wolfram Gloger and Guilhem Lavaux
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/module.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/hash.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/log.h"
|
||||
#endif
|
||||
|
||||
#define TRACE_MODULE wxT("module")
|
||||
|
||||
wxIMPLEMENT_ABSTRACT_CLASS(wxModule, wxObject)
|
||||
|
||||
wxModuleList wxModule::ms_modules;
|
||||
bool wxModule::ms_areInitialized = false;
|
||||
|
||||
void wxModule::RegisterModule(wxModule* module)
|
||||
{
|
||||
module->m_state = State_Registered;
|
||||
ms_modules.push_back(module);
|
||||
}
|
||||
|
||||
void wxModule::UnregisterModule(wxModule* module)
|
||||
{
|
||||
for ( wxModuleList::iterator it = ms_modules.begin();
|
||||
it != ms_modules.end();
|
||||
++it )
|
||||
{
|
||||
if ( *it == module )
|
||||
{
|
||||
ms_modules.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete module;
|
||||
}
|
||||
|
||||
// Collect up all module-derived classes, create an instance of each,
|
||||
// and register them.
|
||||
void wxModule::RegisterModules()
|
||||
{
|
||||
for (wxClassInfo::const_iterator it = wxClassInfo::begin_classinfo(),
|
||||
end = wxClassInfo::end_classinfo();
|
||||
it != end; ++it)
|
||||
{
|
||||
const wxClassInfo* classInfo = *it;
|
||||
|
||||
if ( classInfo->IsKindOf(wxCLASSINFO(wxModule)) &&
|
||||
(classInfo != (& (wxModule::ms_classInfo))) )
|
||||
{
|
||||
wxLogTrace(TRACE_MODULE, wxT("Registering module %s"),
|
||||
classInfo->GetClassName());
|
||||
wxModule* module = (wxModule *)classInfo->CreateObject();
|
||||
wxModule::RegisterModule(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool wxModule::DoInitializeModule(wxModule *module,
|
||||
wxModuleList &initializedModules)
|
||||
{
|
||||
if ( module->m_state == State_Initializing )
|
||||
{
|
||||
wxLogError(_("Circular dependency involving module \"%s\" detected."),
|
||||
module->GetClassInfo()->GetClassName());
|
||||
return false;
|
||||
}
|
||||
|
||||
module->m_state = State_Initializing;
|
||||
|
||||
// translate named dependencies to the normal ones first
|
||||
if ( !module->ResolveNamedDependencies() )
|
||||
return false;
|
||||
|
||||
const wxArrayClassInfo& dependencies = module->m_dependencies;
|
||||
|
||||
// satisfy module dependencies by loading them before the current module
|
||||
for ( unsigned int i = 0; i < dependencies.size(); ++i )
|
||||
{
|
||||
wxClassInfo * cinfo = dependencies[i];
|
||||
|
||||
// Check if the module is already initialized
|
||||
wxModuleList::const_iterator it;
|
||||
for ( it = initializedModules.begin();
|
||||
it != initializedModules.end();
|
||||
++it )
|
||||
{
|
||||
if ( (*it)->GetClassInfo() == cinfo )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( it != initializedModules.end() )
|
||||
{
|
||||
// this dependency is already initialized, nothing to do
|
||||
continue;
|
||||
}
|
||||
|
||||
// find the module in the registered modules list
|
||||
for ( it = ms_modules.begin(); it != ms_modules.end(); ++it )
|
||||
{
|
||||
wxModule *moduleDep = *it;
|
||||
if ( moduleDep->GetClassInfo() == cinfo )
|
||||
{
|
||||
if ( !DoInitializeModule(moduleDep, initializedModules ) )
|
||||
{
|
||||
// failed to initialize a dependency, so fail this one too
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( it == ms_modules.end() )
|
||||
{
|
||||
wxLogError(_("Dependency \"%s\" of module \"%s\" doesn't exist."),
|
||||
cinfo->GetClassName(),
|
||||
module->GetClassInfo()->GetClassName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !module->Init() )
|
||||
{
|
||||
wxLogError(_("Module \"%s\" initialization failed"),
|
||||
module->GetClassInfo()->GetClassName());
|
||||
return false;
|
||||
}
|
||||
|
||||
wxLogTrace(TRACE_MODULE, wxT("Module \"%s\" initialized"),
|
||||
module->GetClassInfo()->GetClassName());
|
||||
|
||||
module->m_state = State_Initialized;
|
||||
initializedModules.push_back(module);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initialize user-defined modules
|
||||
bool wxModule::InitializeModules()
|
||||
{
|
||||
wxModuleList initializedModules;
|
||||
|
||||
for ( wxModuleList::const_iterator it = ms_modules.begin();
|
||||
it != ms_modules.end();
|
||||
++it )
|
||||
{
|
||||
wxModule *module = *it;
|
||||
|
||||
// the module could have been already initialized as dependency of
|
||||
// another one
|
||||
if ( module->m_state == State_Registered )
|
||||
{
|
||||
if ( !DoInitializeModule( module, initializedModules ) )
|
||||
{
|
||||
// failed to initialize all modules, so clean up the already
|
||||
// initialized ones
|
||||
DoCleanUpModules(initializedModules);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remember the real initialisation order
|
||||
ms_modules = initializedModules;
|
||||
|
||||
ms_areInitialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxModule::CleanUpModules()
|
||||
{
|
||||
DoCleanUpModules(ms_modules);
|
||||
|
||||
ms_areInitialized = false;
|
||||
}
|
||||
|
||||
// Clean up all currently initialized modules
|
||||
void wxModule::DoCleanUpModules(const wxModuleList& modules)
|
||||
{
|
||||
// cleanup user-defined modules in the reverse order compared to their
|
||||
// initialization -- this ensures that dependencies are respected
|
||||
for ( wxModuleList::const_reverse_iterator rit = modules.rbegin();
|
||||
rit != modules.rend();
|
||||
++rit )
|
||||
{
|
||||
wxLogTrace(TRACE_MODULE, wxT("Cleanup module %s"),
|
||||
(*rit)->GetClassInfo()->GetClassName());
|
||||
|
||||
wxModule * module = *rit;
|
||||
|
||||
wxASSERT_MSG( module->m_state == State_Initialized,
|
||||
wxT("not initialized module being cleaned up") );
|
||||
|
||||
module->Exit();
|
||||
module->m_state = State_Registered;
|
||||
}
|
||||
|
||||
// clear all modules, even the non-initialized ones
|
||||
for ( wxModuleList::const_iterator it = ms_modules.begin();
|
||||
it != ms_modules.end();
|
||||
++it )
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
|
||||
ms_modules.clear();
|
||||
}
|
||||
|
||||
bool wxModule::ResolveNamedDependencies()
|
||||
{
|
||||
// first resolve required dependencies
|
||||
for ( size_t i = 0; i < m_namedDependencies.size(); ++i )
|
||||
{
|
||||
wxClassInfo *info = wxClassInfo::FindClass(m_namedDependencies[i]);
|
||||
|
||||
if ( !info )
|
||||
{
|
||||
// required dependency not found
|
||||
return false;
|
||||
}
|
||||
|
||||
// add it even if it is not derived from wxModule because
|
||||
// DoInitializeModule() will make sure a module with the same class
|
||||
// info exists and fail if it doesn't
|
||||
m_dependencies.push_back(info);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/msgout.cpp
|
||||
// Purpose: wxMessageOutput implementation
|
||||
// Author: Mattia Barbon
|
||||
// Modified by:
|
||||
// Created: 17.07.02
|
||||
// Copyright: (c) the wxWidgets team
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// headers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/string.h"
|
||||
#include "wx/ffile.h"
|
||||
#include "wx/app.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/log.h"
|
||||
#if wxUSE_GUI
|
||||
#include "wx/msgdlg.h"
|
||||
#endif // wxUSE_GUI
|
||||
#endif
|
||||
|
||||
#include "wx/msgout.h"
|
||||
#include "wx/apptrait.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
#include "wx/msw/private.h"
|
||||
#endif
|
||||
|
||||
// ===========================================================================
|
||||
// implementation
|
||||
// ===========================================================================
|
||||
|
||||
#if wxUSE_BASE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMessageOutput
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxMessageOutput* wxMessageOutput::ms_msgOut = 0;
|
||||
|
||||
wxMessageOutput* wxMessageOutput::Get()
|
||||
{
|
||||
if ( !ms_msgOut && wxTheApp )
|
||||
{
|
||||
ms_msgOut = wxTheApp->GetTraits()->CreateMessageOutput();
|
||||
}
|
||||
|
||||
return ms_msgOut;
|
||||
}
|
||||
|
||||
wxMessageOutput* wxMessageOutput::Set(wxMessageOutput* msgout)
|
||||
{
|
||||
wxMessageOutput* old = ms_msgOut;
|
||||
ms_msgOut = msgout;
|
||||
return old;
|
||||
}
|
||||
|
||||
#if !wxUSE_UTF8_LOCALE_ONLY
|
||||
void wxMessageOutput::DoPrintfWchar(const wxChar *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
wxString out;
|
||||
|
||||
out.PrintfV(format, args);
|
||||
va_end(args);
|
||||
|
||||
Output(out);
|
||||
}
|
||||
#endif // !wxUSE_UTF8_LOCALE_ONLY
|
||||
|
||||
#if wxUSE_UNICODE_UTF8
|
||||
void wxMessageOutput::DoPrintfUtf8(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
wxString out;
|
||||
|
||||
out.PrintfV(format, args);
|
||||
va_end(args);
|
||||
|
||||
Output(out);
|
||||
}
|
||||
#endif // wxUSE_UNICODE_UTF8
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMessageOutputBest
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxMessageOutputBest::Output(const wxString& str)
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
// decide whether to use console output or not
|
||||
wxAppTraits * const traits = wxApp::GetTraitsIfExists();
|
||||
const bool hasStderr = traits ? traits->CanUseStderr() : false;
|
||||
|
||||
if ( !(m_flags & wxMSGOUT_PREFER_MSGBOX) )
|
||||
{
|
||||
if ( hasStderr && traits->WriteToStderr(AppendLineFeedIfNeeded(str)) )
|
||||
return;
|
||||
}
|
||||
|
||||
wxString title;
|
||||
if ( wxTheApp )
|
||||
title = wxTheApp->GetAppDisplayName();
|
||||
else // Use some title to avoid default "Error"
|
||||
title = _("Message");
|
||||
|
||||
::MessageBox(NULL, str.t_str(), title.t_str(), MB_ICONINFORMATION | MB_OK);
|
||||
#else // !__WINDOWS__
|
||||
wxUnusedVar(m_flags);
|
||||
|
||||
// TODO: use the native message box for the other ports too
|
||||
wxMessageOutputStderr::Output(str);
|
||||
#endif // __WINDOWS__/!__WINDOWS__
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMessageOutputWithConv
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxString wxMessageOutputWithConv::AppendLineFeedIfNeeded(const wxString& str)
|
||||
{
|
||||
wxString strLF(str);
|
||||
if ( strLF.empty() || *strLF.rbegin() != '\n' )
|
||||
strLF += '\n';
|
||||
|
||||
return strLF;
|
||||
}
|
||||
|
||||
wxCharBuffer wxMessageOutputWithConv::PrepareForOutput(const wxString& str)
|
||||
{
|
||||
wxString strWithLF = AppendLineFeedIfNeeded(str);
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
// Determine whether the encoding is UTF-16. In that case, the file
|
||||
// should have been opened in "wb" mode, and EOL conversion must be done
|
||||
// here as it won't be done at stdio level.
|
||||
if ( m_conv->GetMBNulLen() == 2 )
|
||||
{
|
||||
strWithLF.Replace("\n", "\r\n");
|
||||
}
|
||||
#endif // __WINDOWS__
|
||||
|
||||
return m_conv->cWX2MB(strWithLF.c_str());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMessageOutputStderr
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxMessageOutputStderr::wxMessageOutputStderr(FILE *fp, const wxMBConv& conv)
|
||||
: wxMessageOutputWithConv(conv),
|
||||
m_fp(fp)
|
||||
{
|
||||
}
|
||||
|
||||
void wxMessageOutputStderr::Output(const wxString& str)
|
||||
{
|
||||
const wxCharBuffer& buf = PrepareForOutput(str);
|
||||
fwrite(buf, buf.length(), 1, m_fp);
|
||||
fflush(m_fp);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMessageOutputDebug
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxMessageOutputDebug::Output(const wxString& str)
|
||||
{
|
||||
#if defined(__WINDOWS__)
|
||||
wxString out(AppendLineFeedIfNeeded(str));
|
||||
out.Replace(wxT("\t"), wxT(" "));
|
||||
out.Replace(wxT("\n"), wxT("\r\n"));
|
||||
::OutputDebugString(out.t_str());
|
||||
#else
|
||||
// TODO: use native debug output function for the other ports too
|
||||
wxMessageOutputStderr::Output(str);
|
||||
#endif // platform
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMessageOutputLog
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxMessageOutputLog::Output(const wxString& str)
|
||||
{
|
||||
wxString out(str);
|
||||
|
||||
out.Replace(wxT("\t"), wxT(" "));
|
||||
|
||||
wxLogMessage(wxT("%s"), out.c_str());
|
||||
}
|
||||
|
||||
#endif // wxUSE_BASE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMessageOutputMessageBox
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_GUI && wxUSE_MSGDLG
|
||||
|
||||
extern WXDLLEXPORT_DATA(const char) wxMessageBoxCaptionStr[] = "Message";
|
||||
|
||||
void wxMessageOutputMessageBox::Output(const wxString& str)
|
||||
{
|
||||
wxString out(str);
|
||||
|
||||
// the native MSW msg box understands the TABs, others don't
|
||||
#ifndef __WINDOWS__
|
||||
out.Replace(wxT("\t"), wxT(" "));
|
||||
#endif
|
||||
|
||||
wxString title = wxT("wxWidgets") ;
|
||||
if (wxTheApp) title = wxTheApp->GetAppDisplayName();
|
||||
|
||||
::wxMessageBox(out, title);
|
||||
}
|
||||
|
||||
#endif // wxUSE_GUI
|
||||
@@ -0,0 +1,203 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/mstream.cpp
|
||||
// Purpose: "Memory stream" classes
|
||||
// Author: Guilhem Lavaux
|
||||
// Modified by: VZ (23.11.00): general code review
|
||||
// Created: 04/01/98
|
||||
// Copyright: (c) Guilhem Lavaux
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_STREAMS
|
||||
|
||||
#include "wx/mstream.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/stream.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMemoryInputStream
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxIMPLEMENT_ABSTRACT_CLASS(wxMemoryInputStream, wxInputStream);
|
||||
|
||||
wxMemoryInputStream::wxMemoryInputStream(const void *data, size_t len)
|
||||
{
|
||||
m_i_streambuf = new wxStreamBuffer(wxStreamBuffer::read);
|
||||
m_i_streambuf->SetBufferIO(const_cast<void *>(data), len);
|
||||
m_i_streambuf->SetIntPosition(0); // seek to start pos
|
||||
m_i_streambuf->Fixed(true);
|
||||
|
||||
m_length = len;
|
||||
}
|
||||
|
||||
wxMemoryInputStream::wxMemoryInputStream(const wxMemoryOutputStream& stream)
|
||||
{
|
||||
const wxFileOffset lenFile = stream.GetLength();
|
||||
if ( lenFile == wxInvalidOffset )
|
||||
{
|
||||
m_i_streambuf = NULL;
|
||||
m_lasterror = wxSTREAM_EOF;
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t len = wx_truncate_cast(size_t, lenFile);
|
||||
wxASSERT_MSG( len == lenFile + size_t(0), wxT("huge files not supported") );
|
||||
|
||||
m_i_streambuf = new wxStreamBuffer(wxStreamBuffer::read);
|
||||
m_i_streambuf->SetBufferIO(len); // create buffer
|
||||
stream.CopyTo(m_i_streambuf->GetBufferStart(), len);
|
||||
m_i_streambuf->SetIntPosition(0); // seek to start pos
|
||||
m_i_streambuf->Fixed(true);
|
||||
m_length = len;
|
||||
}
|
||||
|
||||
void
|
||||
wxMemoryInputStream::InitFromStream(wxInputStream& stream, wxFileOffset lenFile)
|
||||
{
|
||||
if ( lenFile == wxInvalidOffset )
|
||||
lenFile = stream.GetLength();
|
||||
|
||||
if ( lenFile == wxInvalidOffset )
|
||||
{
|
||||
m_i_streambuf = NULL;
|
||||
m_lasterror = wxSTREAM_EOF;
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t len = wx_truncate_cast(size_t, lenFile);
|
||||
wxASSERT_MSG( (wxFileOffset)len == lenFile, wxT("huge files not supported") );
|
||||
|
||||
m_i_streambuf = new wxStreamBuffer(wxStreamBuffer::read);
|
||||
m_i_streambuf->SetBufferIO(len); // create buffer
|
||||
stream.Read(m_i_streambuf->GetBufferStart(), len);
|
||||
m_i_streambuf->SetIntPosition(0); // seek to start pos
|
||||
m_i_streambuf->Fixed(true);
|
||||
m_length = stream.LastRead();
|
||||
}
|
||||
|
||||
bool wxMemoryInputStream::CanRead() const
|
||||
{
|
||||
return m_i_streambuf->GetIntPosition() != m_length;
|
||||
}
|
||||
|
||||
wxMemoryInputStream::~wxMemoryInputStream()
|
||||
{
|
||||
delete m_i_streambuf;
|
||||
}
|
||||
|
||||
char wxMemoryInputStream::Peek()
|
||||
{
|
||||
char *buf = (char *)m_i_streambuf->GetBufferStart();
|
||||
size_t pos = m_i_streambuf->GetIntPosition();
|
||||
if ( pos == m_length )
|
||||
{
|
||||
m_lasterror = wxSTREAM_READ_ERROR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return buf[pos];
|
||||
}
|
||||
|
||||
size_t wxMemoryInputStream::OnSysRead(void *buffer, size_t nbytes)
|
||||
{
|
||||
size_t pos = m_i_streambuf->GetIntPosition();
|
||||
if ( pos == m_length )
|
||||
{
|
||||
m_lasterror = wxSTREAM_EOF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_i_streambuf->Read(buffer, nbytes);
|
||||
m_lasterror = wxSTREAM_NO_ERROR;
|
||||
|
||||
return m_i_streambuf->GetIntPosition() - pos;
|
||||
}
|
||||
|
||||
wxFileOffset wxMemoryInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
|
||||
{
|
||||
return m_i_streambuf->Seek(pos, mode);
|
||||
}
|
||||
|
||||
wxFileOffset wxMemoryInputStream::OnSysTell() const
|
||||
{
|
||||
return m_i_streambuf->Tell();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMemoryOutputStream
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxMemoryOutputStream, wxOutputStream);
|
||||
|
||||
wxMemoryOutputStream::wxMemoryOutputStream(void *data, size_t len)
|
||||
{
|
||||
m_o_streambuf = new wxStreamBuffer(wxStreamBuffer::write);
|
||||
if ( data )
|
||||
m_o_streambuf->SetBufferIO(data, len);
|
||||
m_o_streambuf->Fixed(false);
|
||||
m_o_streambuf->Flushable(false);
|
||||
}
|
||||
|
||||
wxMemoryOutputStream::~wxMemoryOutputStream()
|
||||
{
|
||||
delete m_o_streambuf;
|
||||
}
|
||||
|
||||
size_t wxMemoryOutputStream::OnSysWrite(const void *buffer, size_t nbytes)
|
||||
{
|
||||
size_t oldpos = m_o_streambuf->GetIntPosition();
|
||||
m_o_streambuf->Write(buffer, nbytes);
|
||||
size_t newpos = m_o_streambuf->GetIntPosition();
|
||||
|
||||
// FIXME can someone please explain what this does? (VZ)
|
||||
if ( !newpos )
|
||||
newpos = m_o_streambuf->GetBufferSize();
|
||||
|
||||
return newpos - oldpos;
|
||||
}
|
||||
|
||||
wxFileOffset wxMemoryOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
|
||||
{
|
||||
return m_o_streambuf->Seek(pos, mode);
|
||||
}
|
||||
|
||||
wxFileOffset wxMemoryOutputStream::OnSysTell() const
|
||||
{
|
||||
return m_o_streambuf->Tell();
|
||||
}
|
||||
|
||||
size_t wxMemoryOutputStream::CopyTo(void *buffer, size_t len) const
|
||||
{
|
||||
wxCHECK_MSG( buffer, 0, wxT("must have buffer to CopyTo") );
|
||||
|
||||
if ( len > GetSize() )
|
||||
len = GetSize();
|
||||
|
||||
memcpy(buffer, m_o_streambuf->GetBufferStart(), len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif // wxUSE_STREAMS
|
||||
@@ -0,0 +1,334 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/numformatter.cpp
|
||||
// Purpose: wxNumberFormatter
|
||||
// Author: Fulvio Senore, Vadim Zeitlin
|
||||
// Created: 2010-11-06
|
||||
// Copyright: (c) 2010 wxWidgets team
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/numformatter.h"
|
||||
#include "wx/intl.h"
|
||||
|
||||
#include <locale.h> // for setlocale and LC_ALL
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// local helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Contains information about the locale which was used to initialize our
|
||||
// cached values of the decimal and thousands separators. Notice that it isn't
|
||||
// enough to store just wxLocale because the user code may call setlocale()
|
||||
// directly and storing just C locale string is not enough because we can use
|
||||
// the OS API directly instead of the CRT ones on some platforms. So just store
|
||||
// both.
|
||||
class LocaleId
|
||||
{
|
||||
public:
|
||||
LocaleId()
|
||||
{
|
||||
#if wxUSE_INTL
|
||||
m_wxloc = NULL;
|
||||
#endif // wxUSE_INTL
|
||||
m_cloc = NULL;
|
||||
}
|
||||
|
||||
~LocaleId()
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
#if wxUSE_INTL
|
||||
// Return true if this is the first time this function is called for this
|
||||
// object or if the program locale has changed since the last time it was
|
||||
// called. Otherwise just return false indicating that updating locale-
|
||||
// dependent information is not necessary.
|
||||
bool NotInitializedOrHasChanged()
|
||||
{
|
||||
wxLocale * const wxloc = wxGetLocale();
|
||||
const char * const cloc = setlocale(LC_ALL, NULL);
|
||||
if ( m_wxloc || m_cloc )
|
||||
{
|
||||
if ( m_wxloc == wxloc && strcmp(m_cloc, cloc) == 0 )
|
||||
return false;
|
||||
|
||||
Free();
|
||||
}
|
||||
//else: Not initialized yet.
|
||||
|
||||
m_wxloc = wxloc;
|
||||
m_cloc = wxCRT_StrdupA(cloc);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // wxUSE_INTL
|
||||
|
||||
private:
|
||||
void Free()
|
||||
{
|
||||
#if wxUSE_INTL
|
||||
free(m_cloc);
|
||||
#endif // wxUSE_INTL
|
||||
}
|
||||
|
||||
#if wxUSE_INTL
|
||||
// Non-owned pointer to wxLocale which was used.
|
||||
wxLocale *m_wxloc;
|
||||
#endif // wxUSE_INTL
|
||||
|
||||
// Owned pointer to the C locale string.
|
||||
char *m_cloc;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(LocaleId);
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ============================================================================
|
||||
// wxNumberFormatter implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Locale information accessors
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxChar wxNumberFormatter::GetDecimalSeparator()
|
||||
{
|
||||
#if wxUSE_INTL
|
||||
// Notice that while using static variable here is not MT-safe, the worst
|
||||
// that can happen is that we redo the initialization if we're called
|
||||
// concurrently from more than one thread so it's not a real problem.
|
||||
static wxChar s_decimalSeparator = 0;
|
||||
|
||||
// Remember the locale which was current when we initialized, we must redo
|
||||
// the initialization if the locale changed.
|
||||
static LocaleId s_localeUsedForInit;
|
||||
|
||||
if ( s_localeUsedForInit.NotInitializedOrHasChanged() )
|
||||
{
|
||||
const wxString
|
||||
s = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
|
||||
if ( s.length() == 1 )
|
||||
{
|
||||
s_decimalSeparator = s[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// We really must have something for decimal separator, so fall
|
||||
// back to the C locale default.
|
||||
s_decimalSeparator = '.';
|
||||
}
|
||||
}
|
||||
|
||||
return s_decimalSeparator;
|
||||
#else // !wxUSE_INTL
|
||||
return wxT('.');
|
||||
#endif // wxUSE_INTL/!wxUSE_INTL
|
||||
}
|
||||
|
||||
bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep)
|
||||
{
|
||||
#if wxUSE_INTL
|
||||
static wxChar s_thousandsSeparator = 0;
|
||||
static LocaleId s_localeUsedForInit;
|
||||
|
||||
if ( s_localeUsedForInit.NotInitializedOrHasChanged() )
|
||||
{
|
||||
const wxString
|
||||
s = wxLocale::GetInfo(wxLOCALE_THOUSANDS_SEP, wxLOCALE_CAT_NUMBER);
|
||||
if ( s.length() == 1 )
|
||||
{
|
||||
s_thousandsSeparator = s[0];
|
||||
}
|
||||
//else: Unlike above it's perfectly fine for the thousands separator to
|
||||
// be empty if grouping is not used, so just leave it as 0.
|
||||
}
|
||||
|
||||
if ( !s_thousandsSeparator )
|
||||
return false;
|
||||
|
||||
if ( sep )
|
||||
*sep = s_thousandsSeparator;
|
||||
|
||||
return true;
|
||||
#else // !wxUSE_INTL
|
||||
wxUnusedVar(sep);
|
||||
return false;
|
||||
#endif // wxUSE_INTL/!wxUSE_INTL
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Conversion to string and helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxString wxNumberFormatter::PostProcessIntString(wxString s, int style)
|
||||
{
|
||||
if ( style & Style_WithThousandsSep )
|
||||
AddThousandsSeparators(s);
|
||||
|
||||
wxASSERT_MSG( !(style & Style_NoTrailingZeroes),
|
||||
"Style_NoTrailingZeroes can't be used with integer values" );
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
wxString wxNumberFormatter::ToString(long val, int style)
|
||||
{
|
||||
return PostProcessIntString(wxString::Format("%ld", val), style);
|
||||
}
|
||||
|
||||
#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
||||
|
||||
wxString wxNumberFormatter::ToString(wxLongLong_t val, int style)
|
||||
{
|
||||
return PostProcessIntString(wxString::Format("%" wxLongLongFmtSpec "d", val),
|
||||
style);
|
||||
}
|
||||
|
||||
#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
||||
|
||||
wxString wxNumberFormatter::ToString(wxULongLong_t val, int style)
|
||||
{
|
||||
return PostProcessIntString(wxString::Format("%" wxLongLongFmtSpec "u", val),
|
||||
style);
|
||||
}
|
||||
|
||||
wxString wxNumberFormatter::ToString(double val, int precision, int style)
|
||||
{
|
||||
wxString s = wxString::FromDouble(val,precision);
|
||||
|
||||
if ( style & Style_WithThousandsSep )
|
||||
AddThousandsSeparators(s);
|
||||
|
||||
if ( style & Style_NoTrailingZeroes )
|
||||
RemoveTrailingZeroes(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void wxNumberFormatter::AddThousandsSeparators(wxString& s)
|
||||
{
|
||||
// Thousands separators for numbers in scientific format are not relevant.
|
||||
if ( s.find_first_of("eE") != wxString::npos )
|
||||
return;
|
||||
|
||||
wxChar thousandsSep;
|
||||
if ( !GetThousandsSeparatorIfUsed(&thousandsSep) )
|
||||
return;
|
||||
|
||||
size_t pos = s.find(GetDecimalSeparator());
|
||||
if ( pos == wxString::npos )
|
||||
{
|
||||
// Start grouping at the end of an integer number.
|
||||
pos = s.length();
|
||||
}
|
||||
|
||||
// End grouping at the beginning of the digits -- there could be at a sign
|
||||
// before their start.
|
||||
const size_t start = s.find_first_of("0123456789");
|
||||
|
||||
// We currently group digits by 3 independently of the locale. This is not
|
||||
// the right thing to do and we should use lconv::grouping (under POSIX)
|
||||
// and GetLocaleInfo(LOCALE_SGROUPING) (under MSW) to get information about
|
||||
// the correct grouping to use. This is something that needs to be done at
|
||||
// wxLocale level first and then used here in the future (TODO).
|
||||
const size_t GROUP_LEN = 3;
|
||||
|
||||
while ( pos > start + GROUP_LEN )
|
||||
{
|
||||
pos -= GROUP_LEN;
|
||||
s.insert(pos, thousandsSep);
|
||||
}
|
||||
}
|
||||
|
||||
void wxNumberFormatter::RemoveTrailingZeroes(wxString& s)
|
||||
{
|
||||
// If number is in scientific format, trailing zeroes belong to the exponent and cannot be removed.
|
||||
if ( s.find_first_of("eE") != wxString::npos )
|
||||
return;
|
||||
|
||||
const size_t posDecSep = s.find(GetDecimalSeparator());
|
||||
// No decimal point => removing trailing zeroes irrelevant for integer number.
|
||||
if ( posDecSep == wxString::npos )
|
||||
return;
|
||||
wxCHECK_RET( posDecSep, "Can't start with decimal separator" );
|
||||
|
||||
// Find the last character to keep.
|
||||
size_t posLastNonZero = s.find_last_not_of("0");
|
||||
|
||||
// If it's the decimal separator itself, don't keep it neither.
|
||||
if ( posLastNonZero == posDecSep )
|
||||
posLastNonZero--;
|
||||
|
||||
s.erase(posLastNonZero + 1);
|
||||
// Remove sign from orphaned zero.
|
||||
if ( s.compare("-0") == 0 )
|
||||
s = "0";
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Conversion from strings
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxNumberFormatter::RemoveThousandsSeparators(wxString& s)
|
||||
{
|
||||
wxChar thousandsSep;
|
||||
if ( !GetThousandsSeparatorIfUsed(&thousandsSep) )
|
||||
return;
|
||||
|
||||
s.Replace(wxString(thousandsSep), wxString());
|
||||
}
|
||||
|
||||
bool wxNumberFormatter::FromString(wxString s, long *val)
|
||||
{
|
||||
RemoveThousandsSeparators(s);
|
||||
return s.ToLong(val);
|
||||
}
|
||||
|
||||
#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
||||
|
||||
bool wxNumberFormatter::FromString(wxString s, wxLongLong_t *val)
|
||||
{
|
||||
RemoveThousandsSeparators(s);
|
||||
return s.ToLongLong(val);
|
||||
}
|
||||
|
||||
#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
||||
|
||||
bool wxNumberFormatter::FromString(wxString s, wxULongLong_t *val)
|
||||
{
|
||||
RemoveThousandsSeparators(s);
|
||||
|
||||
// wxString::ToULongLong() does accept minus sign for unsigned integers,
|
||||
// consistently with the standard functions behaviour, e.g. strtoul() does
|
||||
// the same thing, but here we really want to accept the "true" unsigned
|
||||
// numbers only, so check for leading minus, possibly preceded by some
|
||||
// whitespace.
|
||||
for ( wxString::const_iterator it = s.begin(); it != s.end(); ++it )
|
||||
{
|
||||
if ( *it == '-' )
|
||||
return false;
|
||||
|
||||
if ( *it != ' ' && *it != '\t' )
|
||||
break;
|
||||
}
|
||||
|
||||
return s.ToULongLong(val);
|
||||
}
|
||||
|
||||
bool wxNumberFormatter::FromString(wxString s, double *val)
|
||||
{
|
||||
RemoveThousandsSeparators(s);
|
||||
return s.ToDouble(val);
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/object.cpp
|
||||
// Purpose: wxObject implementation
|
||||
// Author: Julian Smart
|
||||
// Modified by: Ron Lee
|
||||
// Created: 04/01/98
|
||||
// Copyright: (c) 1998 Julian Smart
|
||||
// (c) 2001 Ron Lee <ron@debian.org>
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/object.h"
|
||||
#include "wx/hash.h"
|
||||
#include "wx/memory.h"
|
||||
#include "wx/crt.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// we must disable optimizations for VC.NET because otherwise its too eager
|
||||
// linker discards wxClassInfo objects in release build thus breaking many,
|
||||
// many things
|
||||
#if defined __VISUALC__
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
|
||||
#if wxUSE_EXTENDED_RTTI
|
||||
const wxClassInfo* wxObject::ms_classParents[] = { NULL } ;
|
||||
wxObject* wxVariantOfPtrToObjectConverterwxObject ( const wxAny &data )
|
||||
{ return data.As<wxObject*>(); }
|
||||
wxAny wxObjectToVariantConverterwxObject ( wxObject *data )
|
||||
{ return wxAny( dynamic_cast<wxObject*> (data) ) ; }
|
||||
|
||||
wxClassInfo wxObject::ms_classInfo(ms_classParents , wxEmptyString , wxT("wxObject"),
|
||||
(int) sizeof(wxObject), \
|
||||
(wxObjectConstructorFn) 0 ,
|
||||
NULL,NULL,0 , 0 ,
|
||||
0 , wxVariantOfPtrToObjectConverterwxObject , 0 , wxObjectToVariantConverterwxObject);
|
||||
|
||||
template<> void wxStringWriteValue(wxString & , wxObject* const & ){ wxFAIL_MSG("unreachable"); }
|
||||
template<> void wxStringWriteValue(wxString & , wxObject const & ){ wxFAIL_MSG("unreachable"); }
|
||||
|
||||
wxClassTypeInfo s_typeInfo(wxT_OBJECT_PTR , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject*).name() ) ;
|
||||
wxClassTypeInfo s_typeInfowxObject(wxT_OBJECT , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject).name() ) ;
|
||||
#else
|
||||
wxClassInfo wxObject::ms_classInfo( wxT("wxObject"), 0, 0,
|
||||
(int) sizeof(wxObject),
|
||||
(wxObjectConstructorFn) 0 );
|
||||
#endif
|
||||
|
||||
// restore optimizations
|
||||
#if defined __VISUALC__
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
wxClassInfo* wxClassInfo::sm_first = NULL;
|
||||
wxHashTable* wxClassInfo::sm_classTable = NULL;
|
||||
|
||||
// when using XTI, this method is already implemented inline inside
|
||||
// wxDECLARE_DYNAMIC_CLASS but otherwise we intentionally make this function
|
||||
// non-inline because this allows us to have a non-inline virtual function in
|
||||
// all wx classes and this solves linking problems for HP-UX native toolchain
|
||||
// and possibly others (we could make dtor non-inline as well but it's more
|
||||
// useful to keep it inline than this function)
|
||||
#if !wxUSE_EXTENDED_RTTI
|
||||
|
||||
wxClassInfo *wxObject::GetClassInfo() const
|
||||
{
|
||||
return &wxObject::ms_classInfo;
|
||||
}
|
||||
|
||||
#endif // wxUSE_EXTENDED_RTTI
|
||||
|
||||
// this variable exists only so that we can avoid 'always true/false' warnings
|
||||
const bool wxFalse = false;
|
||||
|
||||
// Is this object a kind of (a subclass of) 'info'?
|
||||
// E.g. is wxWindow a kind of wxObject?
|
||||
// Go from this class to superclass, taking into account
|
||||
// two possible base classes.
|
||||
bool wxObject::IsKindOf(const wxClassInfo *info) const
|
||||
{
|
||||
const wxClassInfo *thisInfo = GetClassInfo();
|
||||
return (thisInfo) ? thisInfo->IsKindOf(info) : false ;
|
||||
}
|
||||
|
||||
#if wxUSE_MEMORY_TRACING && defined( new )
|
||||
#undef new
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WX_WANT_NEW_SIZET_WXCHAR_INT
|
||||
void *wxObject::operator new ( size_t size, const wxChar *fileName, int lineNum )
|
||||
{
|
||||
return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WX_WANT_DELETE_VOID
|
||||
void wxObject::operator delete ( void *buf )
|
||||
{
|
||||
wxDebugFree(buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WX_WANT_DELETE_VOID_CONSTCHAR_SIZET
|
||||
void wxObject::operator delete ( void *buf, const char *_fname, size_t _line )
|
||||
{
|
||||
wxDebugFree(buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WX_WANT_DELETE_VOID_WXCHAR_INT
|
||||
void wxObject::operator delete ( void *buf, const wxChar *WXUNUSED(fileName), int WXUNUSED(lineNum) )
|
||||
{
|
||||
wxDebugFree(buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WX_WANT_ARRAY_NEW_SIZET_WXCHAR_INT
|
||||
void *wxObject::operator new[] ( size_t size, const wxChar* fileName, int lineNum )
|
||||
{
|
||||
return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WX_WANT_ARRAY_DELETE_VOID
|
||||
void wxObject::operator delete[] ( void *buf )
|
||||
{
|
||||
wxDebugFree(buf, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WX_WANT_ARRAY_DELETE_VOID_WXCHAR_INT
|
||||
void wxObject::operator delete[] (void * buf, const wxChar* WXUNUSED(fileName), int WXUNUSED(lineNum) )
|
||||
{
|
||||
wxDebugFree(buf, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxClassInfo
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxClassInfo::~wxClassInfo()
|
||||
{
|
||||
// remove this object from the linked list of all class infos: if we don't
|
||||
// do it, loading/unloading a DLL containing static wxClassInfo objects is
|
||||
// not going to work
|
||||
if ( this == sm_first )
|
||||
{
|
||||
sm_first = m_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
wxClassInfo *info = sm_first;
|
||||
while (info)
|
||||
{
|
||||
if ( info->m_next == this )
|
||||
{
|
||||
info->m_next = m_next;
|
||||
break;
|
||||
}
|
||||
|
||||
info = info->m_next;
|
||||
}
|
||||
}
|
||||
Unregister();
|
||||
}
|
||||
|
||||
wxClassInfo *wxClassInfo::FindClass(const wxString& className)
|
||||
{
|
||||
if ( sm_classTable )
|
||||
{
|
||||
return (wxClassInfo *)wxClassInfo::sm_classTable->Get(className);
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( wxClassInfo *info = sm_first; info ; info = info->m_next )
|
||||
{
|
||||
if ( className == info->GetClassName() )
|
||||
return info;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Reentrance can occur on some platforms (Solaris for one), as the use of hash
|
||||
// and string objects can cause other modules to load and register classes
|
||||
// before the original call returns. This is handled by keeping the hash table
|
||||
// local when it is first created and only assigning it to the global variable
|
||||
// when the function is ready to return.
|
||||
//
|
||||
// That does make the assumption that after the function has completed the
|
||||
// first time the problem will no longer happen; all the modules it depends on
|
||||
// will have been loaded. The assumption is checked using the 'entry' variable
|
||||
// as a reentrance guard, it checks that once the hash table is global it is
|
||||
// not accessed multiple times simulateously.
|
||||
|
||||
void wxClassInfo::Register()
|
||||
{
|
||||
#if wxDEBUG_LEVEL
|
||||
// reentrance guard - see note above
|
||||
static int entry = 0;
|
||||
#endif // wxDEBUG_LEVEL
|
||||
|
||||
wxHashTable *classTable;
|
||||
|
||||
if ( !sm_classTable )
|
||||
{
|
||||
// keep the hash local initially, reentrance is possible
|
||||
classTable = new wxHashTable(wxKEY_STRING);
|
||||
}
|
||||
else
|
||||
{
|
||||
// guard againt reentrance once the global has been created
|
||||
wxASSERT_MSG(++entry == 1, wxT("wxClassInfo::Register() reentrance"));
|
||||
classTable = sm_classTable;
|
||||
}
|
||||
|
||||
// Using wxIMPLEMENT_DYNAMIC_CLASS() macro twice (which may happen if you
|
||||
// link any object module twice mistakenly, or link twice against wx shared
|
||||
// library) will break this function because it will enter an infinite loop
|
||||
// and eventually die with "out of memory" - as this is quite hard to
|
||||
// detect if you're unaware of this, try to do some checks here.
|
||||
wxASSERT_MSG( classTable->Get(m_className) == NULL,
|
||||
wxString::Format
|
||||
(
|
||||
wxT("Class \"%s\" already in RTTI table - have you used wxIMPLEMENT_DYNAMIC_CLASS() multiple times or linked some object file twice)?"),
|
||||
m_className
|
||||
)
|
||||
);
|
||||
|
||||
classTable->Put(m_className, (wxObject *)this);
|
||||
|
||||
// if we're using a local hash we need to try to make it global
|
||||
if ( sm_classTable != classTable )
|
||||
{
|
||||
if ( !sm_classTable )
|
||||
{
|
||||
// make the hash global
|
||||
sm_classTable = classTable;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the gobal hash has already been created by a reentrant call,
|
||||
// so delete the local hash and try again
|
||||
delete classTable;
|
||||
Register();
|
||||
}
|
||||
}
|
||||
|
||||
#if wxDEBUG_LEVEL
|
||||
entry = 0;
|
||||
#endif // wxDEBUG_LEVEL
|
||||
}
|
||||
|
||||
void wxClassInfo::Unregister()
|
||||
{
|
||||
if ( sm_classTable )
|
||||
{
|
||||
sm_classTable->Delete(m_className);
|
||||
if ( sm_classTable->GetCount() == 0 )
|
||||
{
|
||||
wxDELETE(sm_classTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxObject *wxCreateDynamicObject(const wxString& name)
|
||||
{
|
||||
if ( wxClassInfo::sm_classTable )
|
||||
{
|
||||
wxClassInfo *info = (wxClassInfo *)wxClassInfo::sm_classTable->Get(name);
|
||||
return info ? info->CreateObject() : NULL;
|
||||
}
|
||||
else // no sm_classTable yet
|
||||
{
|
||||
for ( wxClassInfo *info = wxClassInfo::sm_first;
|
||||
info;
|
||||
info = info->m_next )
|
||||
{
|
||||
if (info->m_className && wxStrcmp(info->m_className, name) == 0)
|
||||
return info->CreateObject();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// iterator interface
|
||||
wxClassInfo::const_iterator::value_type
|
||||
wxClassInfo::const_iterator::operator*() const
|
||||
{
|
||||
return (wxClassInfo*)m_node->GetData();
|
||||
}
|
||||
|
||||
wxClassInfo::const_iterator& wxClassInfo::const_iterator::operator++()
|
||||
{
|
||||
m_node = m_table->Next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const wxClassInfo::const_iterator wxClassInfo::const_iterator::operator++(int)
|
||||
{
|
||||
wxClassInfo::const_iterator tmp = *this;
|
||||
m_node = m_table->Next();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
wxClassInfo::const_iterator wxClassInfo::begin_classinfo()
|
||||
{
|
||||
sm_classTable->BeginFind();
|
||||
|
||||
return const_iterator(sm_classTable->Next(), sm_classTable);
|
||||
}
|
||||
|
||||
wxClassInfo::const_iterator wxClassInfo::end_classinfo()
|
||||
{
|
||||
return const_iterator(NULL, NULL);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxObjectRefData
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxRefCounter::DecRef()
|
||||
{
|
||||
wxASSERT_MSG( m_count > 0, "invalid ref data count" );
|
||||
|
||||
if ( --m_count == 0 )
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxObject
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxObject::Ref(const wxObject& clone)
|
||||
{
|
||||
// nothing to be done
|
||||
if (m_refData == clone.m_refData)
|
||||
return;
|
||||
|
||||
// delete reference to old data
|
||||
UnRef();
|
||||
|
||||
// reference new data
|
||||
if ( clone.m_refData )
|
||||
{
|
||||
m_refData = clone.m_refData;
|
||||
m_refData->IncRef();
|
||||
}
|
||||
}
|
||||
|
||||
void wxObject::UnRef()
|
||||
{
|
||||
if ( m_refData )
|
||||
{
|
||||
m_refData->DecRef();
|
||||
m_refData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void wxObject::AllocExclusive()
|
||||
{
|
||||
if ( !m_refData )
|
||||
{
|
||||
m_refData = CreateRefData();
|
||||
}
|
||||
else if ( m_refData->GetRefCount() > 1 )
|
||||
{
|
||||
// note that ref is not going to be destroyed in this case
|
||||
const wxObjectRefData* ref = m_refData;
|
||||
UnRef();
|
||||
|
||||
// ... so we can still access it
|
||||
m_refData = CloneRefData(ref);
|
||||
}
|
||||
//else: ref count is 1, we are exclusive owners of m_refData anyhow
|
||||
|
||||
wxASSERT_MSG( m_refData && m_refData->GetRefCount() == 1,
|
||||
wxT("wxObject::AllocExclusive() failed.") );
|
||||
}
|
||||
|
||||
wxObjectRefData *wxObject::CreateRefData() const
|
||||
{
|
||||
// if you use AllocExclusive() you must override this method
|
||||
wxFAIL_MSG( wxT("CreateRefData() must be overridden if called!") );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wxObjectRefData *
|
||||
wxObject::CloneRefData(const wxObjectRefData * WXUNUSED(data)) const
|
||||
{
|
||||
// if you use AllocExclusive() you must override this method
|
||||
wxFAIL_MSG( wxT("CloneRefData() must be overridden if called!") );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/ownerdrwcmn.cpp
|
||||
// Purpose: wxOwnerDrawn class methods common to all platforms
|
||||
// Author: Marcin Malich
|
||||
// Modified by:
|
||||
// Created: 2009-09-22
|
||||
// Copyright: (c) 2009 Marcin Malich <me@malcom.pl>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_OWNER_DRAWN
|
||||
|
||||
#include "wx/ownerdrw.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/window.h"
|
||||
#include "wx/font.h"
|
||||
#include "wx/colour.h"
|
||||
#include "wx/dcmemory.h"
|
||||
#include "wx/settings.h"
|
||||
#include "wx/utils.h"
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constants for base class
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int wxOwnerDrawnBase::ms_defaultMargin = 3;
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
bool wxOwnerDrawnBase::OnMeasureItem(size_t *width, size_t *height)
|
||||
{
|
||||
if ( IsOwnerDrawn() )
|
||||
{
|
||||
wxMemoryDC dc;
|
||||
wxFont font;
|
||||
GetFontToUse(font);
|
||||
dc.SetFont(font);
|
||||
|
||||
// item name/text without mnemonics
|
||||
wxString name = wxStripMenuCodes(GetName(), wxStrip_Mnemonics);
|
||||
|
||||
wxCoord w, h;
|
||||
dc.GetTextExtent(name, &w, &h);
|
||||
|
||||
*width = w + m_margin;
|
||||
*height = h;
|
||||
}
|
||||
else
|
||||
{
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxOwnerDrawnBase::GetFontToUse(wxFont& font) const
|
||||
{
|
||||
font = m_font.IsOk() ? m_font : *wxNORMAL_FONT;
|
||||
}
|
||||
|
||||
void wxOwnerDrawnBase::GetColourToUse(wxODStatus stat, wxColour& colText, wxColour& colBack) const
|
||||
{
|
||||
if ( stat & wxODSelected )
|
||||
{
|
||||
colText = wxSystemSettings::GetColour(
|
||||
!(stat & wxODDisabled) ? wxSYS_COLOUR_HIGHLIGHTTEXT
|
||||
: wxSYS_COLOUR_GRAYTEXT);
|
||||
|
||||
colBack = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// fall back to default colors if none explicitly specified
|
||||
|
||||
if ( stat & wxODDisabled )
|
||||
{
|
||||
colText = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
|
||||
}
|
||||
else
|
||||
{
|
||||
colText = m_colText.IsOk() ? m_colText
|
||||
: wxSystemSettings::GetColour(wxSYS_COLOUR_MENUTEXT);
|
||||
}
|
||||
|
||||
colBack = m_colBack.IsOk() ? m_colBack
|
||||
: wxSystemSettings::GetColour(wxSYS_COLOUR_MENU);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_OWNER_DRAWN
|
||||
@@ -0,0 +1,171 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/persist.cpp
|
||||
// Purpose: common persistence support classes
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2009-01-20
|
||||
// Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_CONFIG
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include "wx/persist.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
wxPersistenceManager* gs_manager = NULL;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ============================================================================
|
||||
// wxPersistenceManager implementation
|
||||
// ============================================================================
|
||||
|
||||
/* static */
|
||||
void wxPersistenceManager::Set(wxPersistenceManager& manager)
|
||||
{
|
||||
gs_manager = &manager;
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxPersistenceManager& wxPersistenceManager::Get()
|
||||
{
|
||||
if ( !gs_manager )
|
||||
{
|
||||
static wxPersistenceManager s_manager;
|
||||
|
||||
gs_manager = &s_manager;
|
||||
}
|
||||
|
||||
return *gs_manager;
|
||||
}
|
||||
|
||||
wxPersistenceManager::~wxPersistenceManager()
|
||||
{
|
||||
}
|
||||
|
||||
wxString
|
||||
wxPersistenceManager::GetKey(const wxPersistentObject& who,
|
||||
const wxString& name) const
|
||||
{
|
||||
wxString key("Persistent_Options"); // TODO: make this configurable
|
||||
key << wxCONFIG_PATH_SEPARATOR << who.GetKind()
|
||||
<< wxCONFIG_PATH_SEPARATOR << who.GetName()
|
||||
<< wxCONFIG_PATH_SEPARATOR << name;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
wxPersistentObject *wxPersistenceManager::Find(void *obj) const
|
||||
{
|
||||
const wxPersistentObjectsMap::const_iterator
|
||||
it = m_persistentObjects.find(obj);
|
||||
return it == m_persistentObjects.end() ? NULL : it->second;
|
||||
}
|
||||
|
||||
wxPersistentObject *
|
||||
wxPersistenceManager::Register(void *obj, wxPersistentObject *po)
|
||||
{
|
||||
if ( wxPersistentObject *old = Find(obj) )
|
||||
{
|
||||
wxFAIL_MSG( "object is already registered" );
|
||||
|
||||
delete po; // still avoid the memory leaks
|
||||
return old;
|
||||
}
|
||||
|
||||
m_persistentObjects[obj] = po;
|
||||
|
||||
return po;
|
||||
}
|
||||
|
||||
void wxPersistenceManager::Unregister(void *obj)
|
||||
{
|
||||
wxPersistentObjectsMap::iterator it = m_persistentObjects.find(obj);
|
||||
wxCHECK_RET( it != m_persistentObjects.end(), "not registered" );
|
||||
|
||||
wxPersistentObject * const po = it->second;
|
||||
m_persistentObjects.erase(it);
|
||||
delete po;
|
||||
}
|
||||
|
||||
void wxPersistenceManager::Save(void *obj)
|
||||
{
|
||||
if ( !m_doSave )
|
||||
return;
|
||||
|
||||
wxPersistentObjectsMap::iterator it = m_persistentObjects.find(obj);
|
||||
wxCHECK_RET( it != m_persistentObjects.end(), "not registered" );
|
||||
|
||||
it->second->Save();
|
||||
}
|
||||
|
||||
bool wxPersistenceManager::Restore(void *obj)
|
||||
{
|
||||
if ( !m_doRestore )
|
||||
return false;
|
||||
|
||||
wxPersistentObjectsMap::iterator it = m_persistentObjects.find(obj);
|
||||
wxCHECK_MSG( it != m_persistentObjects.end(), false, "not registered" );
|
||||
|
||||
return it->second->Restore();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
inline bool
|
||||
DoSaveValue(wxConfigBase *conf, const wxString& key, T value)
|
||||
{
|
||||
return conf && conf->Write(key, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
DoRestoreValue(wxConfigBase *conf, const wxString& key, T *value)
|
||||
{
|
||||
return conf && conf->Read(key, value);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
#define wxPERSIST_DEFINE_SAVE_RESTORE_FOR(Type) \
|
||||
bool wxPersistenceManager::SaveValue(const wxPersistentObject& who, \
|
||||
const wxString& name, \
|
||||
Type value) \
|
||||
{ \
|
||||
return DoSaveValue(GetConfig(), GetKey(who, name), value); \
|
||||
} \
|
||||
\
|
||||
bool wxPersistenceManager::RestoreValue(const wxPersistentObject& who, \
|
||||
const wxString& name, \
|
||||
Type *value) \
|
||||
{ \
|
||||
return DoRestoreValue(GetConfig(), GetKey(who, name), value); \
|
||||
}
|
||||
|
||||
wxPERSIST_DEFINE_SAVE_RESTORE_FOR(bool)
|
||||
wxPERSIST_DEFINE_SAVE_RESTORE_FOR(int)
|
||||
wxPERSIST_DEFINE_SAVE_RESTORE_FOR(long)
|
||||
wxPERSIST_DEFINE_SAVE_RESTORE_FOR(wxString)
|
||||
|
||||
#undef wxPERSIST_DEFINE_SAVE_RESTORE_FOR
|
||||
|
||||
#endif // wxUSE_CONFIG
|
||||
@@ -0,0 +1,375 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/platinfo.cpp
|
||||
// Purpose: implements wxPlatformInfo class
|
||||
// Author: Francesco Montorsi
|
||||
// Modified by:
|
||||
// Created: 07.07.2006 (based on wxToolkitInfo)
|
||||
// Copyright: (c) 2006 Francesco Montorsi
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/platinfo.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/app.h"
|
||||
#include "wx/utils.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include "wx/apptrait.h"
|
||||
|
||||
// global object
|
||||
// VERY IMPORTANT: do not use the default constructor since it would
|
||||
// try to init the wxPlatformInfo instance using
|
||||
// gs_platInfo itself!
|
||||
static wxPlatformInfo gs_platInfo(wxPORT_UNKNOWN);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constants
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Keep "Unknown" entries to avoid breaking the indexes
|
||||
|
||||
static const wxChar* const wxOperatingSystemIdNames[] =
|
||||
{
|
||||
wxT("Apple Mac OS"),
|
||||
wxT("Apple Mac OS X"),
|
||||
|
||||
wxT("Unknown"), // STL build: cannot use _() to translate strings here
|
||||
wxT("Microsoft Windows NT"),
|
||||
wxT("Unknown"),
|
||||
wxT("Unknown"),
|
||||
|
||||
wxT("Linux"),
|
||||
wxT("FreeBSD"),
|
||||
wxT("OpenBSD"),
|
||||
wxT("NetBSD"),
|
||||
|
||||
wxT("SunOS"),
|
||||
wxT("AIX"),
|
||||
wxT("HPUX"),
|
||||
|
||||
wxT("Other Unix"),
|
||||
wxT("Other Unix"),
|
||||
|
||||
wxT("Unknown"),
|
||||
wxT("Unknown"),
|
||||
|
||||
};
|
||||
|
||||
static const wxChar* const wxPortIdNames[] =
|
||||
{
|
||||
wxT("wxBase"),
|
||||
wxT("wxMSW"),
|
||||
wxT("wxMotif"),
|
||||
wxT("wxGTK"),
|
||||
wxT("wxDFB"),
|
||||
wxT("wxX11"),
|
||||
wxT("Unknown"),
|
||||
wxT("wxMac"),
|
||||
wxT("wxCocoa"),
|
||||
wxT("Unknown"),
|
||||
wxT("wxQT")
|
||||
};
|
||||
|
||||
static const wxChar* const wxBitnessNames[] =
|
||||
{
|
||||
wxT("32 bit"),
|
||||
wxT("64 bit")
|
||||
};
|
||||
|
||||
static const wxChar* const wxEndiannessNames[] =
|
||||
{
|
||||
wxT("Big endian"),
|
||||
wxT("Little endian"),
|
||||
wxT("PDP endian")
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// local functions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// returns the logarithm in base 2 of 'value'; this maps the enum values to the
|
||||
// corresponding indexes of the string arrays above
|
||||
static unsigned wxGetIndexFromEnumValue(int value)
|
||||
{
|
||||
wxCHECK_MSG( value, (unsigned)-1, wxT("invalid enum value") );
|
||||
|
||||
int n = 0;
|
||||
while ( !(value & 1) )
|
||||
{
|
||||
value >>= 1;
|
||||
n++;
|
||||
}
|
||||
|
||||
wxASSERT_MSG( value == 1, wxT("more than one bit set in enum value") );
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxPlatformInfo
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxPlatformInfo::wxPlatformInfo()
|
||||
{
|
||||
// just copy platform info for currently running platform
|
||||
*this = Get();
|
||||
}
|
||||
|
||||
wxPlatformInfo::wxPlatformInfo(wxPortId pid, int tkMajor, int tkMinor,
|
||||
wxOperatingSystemId id, int osMajor, int osMinor,
|
||||
wxBitness bitness,
|
||||
wxEndianness endian,
|
||||
bool usingUniversal)
|
||||
{
|
||||
m_initializedForCurrentPlatform = false;
|
||||
|
||||
m_tkVersionMajor = tkMajor;
|
||||
m_tkVersionMinor = tkMinor;
|
||||
m_tkVersionMicro = -1;
|
||||
m_port = pid;
|
||||
m_usingUniversal = usingUniversal;
|
||||
|
||||
m_os = id;
|
||||
m_osVersionMajor = osMajor;
|
||||
m_osVersionMinor = osMinor;
|
||||
m_osVersionMicro = -1;
|
||||
|
||||
m_endian = endian;
|
||||
m_bitness = bitness;
|
||||
}
|
||||
|
||||
bool wxPlatformInfo::operator==(const wxPlatformInfo &t) const
|
||||
{
|
||||
return m_tkVersionMajor == t.m_tkVersionMajor &&
|
||||
m_tkVersionMinor == t.m_tkVersionMinor &&
|
||||
m_tkVersionMicro == t.m_tkVersionMicro &&
|
||||
m_osVersionMajor == t.m_osVersionMajor &&
|
||||
m_osVersionMinor == t.m_osVersionMinor &&
|
||||
m_osVersionMicro == t.m_osVersionMicro &&
|
||||
m_os == t.m_os &&
|
||||
m_osDesc == t.m_osDesc &&
|
||||
m_ldi == t.m_ldi &&
|
||||
m_desktopEnv == t.m_desktopEnv &&
|
||||
m_port == t.m_port &&
|
||||
m_usingUniversal == t.m_usingUniversal &&
|
||||
m_bitness == t.m_bitness &&
|
||||
m_endian == t.m_endian;
|
||||
}
|
||||
|
||||
void wxPlatformInfo::InitForCurrentPlatform()
|
||||
{
|
||||
m_initializedForCurrentPlatform = true;
|
||||
|
||||
// autodetect all informations
|
||||
const wxAppTraits * const traits = wxApp::GetTraitsIfExists();
|
||||
if ( !traits )
|
||||
{
|
||||
wxFAIL_MSG( wxT("failed to initialize wxPlatformInfo") );
|
||||
|
||||
m_port = wxPORT_UNKNOWN;
|
||||
m_usingUniversal = false;
|
||||
m_tkVersionMajor =
|
||||
m_tkVersionMinor =
|
||||
m_tkVersionMicro = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_port = traits->GetToolkitVersion(&m_tkVersionMajor, &m_tkVersionMinor,
|
||||
&m_tkVersionMicro);
|
||||
m_usingUniversal = traits->IsUsingUniversalWidgets();
|
||||
m_desktopEnv = traits->GetDesktopEnvironment();
|
||||
}
|
||||
|
||||
m_os = wxGetOsVersion(&m_osVersionMajor, &m_osVersionMinor, &m_osVersionMicro);
|
||||
m_osDesc = wxGetOsDescription();
|
||||
m_endian = wxIsPlatformLittleEndian() ? wxENDIAN_LITTLE : wxENDIAN_BIG;
|
||||
m_bitness = wxIsPlatform64Bit() ? wxBITNESS_64 : wxBITNESS_32;
|
||||
m_cpuArch = wxGetCpuArchitectureName();
|
||||
|
||||
#ifdef __LINUX__
|
||||
m_ldi = wxGetLinuxDistributionInfo();
|
||||
#endif
|
||||
// else: leave m_ldi empty
|
||||
}
|
||||
|
||||
/* static */
|
||||
const wxPlatformInfo& wxPlatformInfo::Get()
|
||||
{
|
||||
static bool initialized = false;
|
||||
if ( !initialized )
|
||||
{
|
||||
gs_platInfo.InitForCurrentPlatform();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
return gs_platInfo;
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxString wxPlatformInfo::GetOperatingSystemDirectory()
|
||||
{
|
||||
return wxGetOSDirectory();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxPlatformInfo - enum -> string conversions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxString wxPlatformInfo::GetOperatingSystemFamilyName(wxOperatingSystemId os)
|
||||
{
|
||||
const wxChar* string = wxT("Unknown");
|
||||
if ( os & wxOS_MAC )
|
||||
string = wxT("Macintosh");
|
||||
else if ( os & wxOS_WINDOWS )
|
||||
string = wxT("Windows");
|
||||
else if ( os & wxOS_UNIX )
|
||||
string = wxT("Unix");
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
wxString wxPlatformInfo::GetOperatingSystemIdName(wxOperatingSystemId os)
|
||||
{
|
||||
const unsigned idx = wxGetIndexFromEnumValue(os);
|
||||
|
||||
wxCHECK_MSG( idx < WXSIZEOF(wxOperatingSystemIdNames), wxEmptyString,
|
||||
wxT("invalid OS id") );
|
||||
|
||||
return wxOperatingSystemIdNames[idx];
|
||||
}
|
||||
|
||||
wxString wxPlatformInfo::GetPortIdName(wxPortId port, bool usingUniversal)
|
||||
{
|
||||
wxString ret;
|
||||
|
||||
const unsigned idx = wxGetIndexFromEnumValue(port);
|
||||
|
||||
wxCHECK_MSG( idx < WXSIZEOF(wxPortIdNames), ret,
|
||||
wxT("invalid port id") );
|
||||
|
||||
ret = wxPortIdNames[idx];
|
||||
|
||||
if ( usingUniversal )
|
||||
ret += wxT("/wxUniversal");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
wxString wxPlatformInfo::GetPortIdShortName(wxPortId port, bool usingUniversal)
|
||||
{
|
||||
wxString ret;
|
||||
|
||||
const unsigned idx = wxGetIndexFromEnumValue(port);
|
||||
|
||||
wxCHECK_MSG( idx < WXSIZEOF(wxPortIdNames), ret,
|
||||
wxT("invalid port id") );
|
||||
|
||||
ret = wxPortIdNames[idx];
|
||||
ret = ret.Mid(2).Lower(); // remove 'wx' prefix
|
||||
|
||||
if ( usingUniversal )
|
||||
ret += wxT("univ");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
wxString wxPlatformInfo::GetBitnessName(wxBitness bitness)
|
||||
{
|
||||
wxCOMPILE_TIME_ASSERT( WXSIZEOF(wxBitnessNames) == wxBITNESS_MAX,
|
||||
wxBitnessNamesMismatch );
|
||||
|
||||
return wxBitnessNames[bitness];
|
||||
}
|
||||
|
||||
wxString wxPlatformInfo::GetEndiannessName(wxEndianness end)
|
||||
{
|
||||
wxCOMPILE_TIME_ASSERT( WXSIZEOF(wxEndiannessNames) == wxENDIAN_MAX,
|
||||
wxEndiannessNamesMismatch );
|
||||
|
||||
return wxEndiannessNames[end];
|
||||
}
|
||||
|
||||
bool wxPlatformInfo::CheckOSVersion(int major, int minor, int micro) const
|
||||
{
|
||||
// If this instance of wxPlatformInfo has been initialized by InitForCurrentPlatform()
|
||||
// this check gets forwarded to the wxCheckOsVersion which might do more than a simple
|
||||
// number check if supported by the platform
|
||||
if (m_initializedForCurrentPlatform)
|
||||
return wxCheckOsVersion(major, minor, micro);
|
||||
else
|
||||
return DoCheckVersion(GetOSMajorVersion(),
|
||||
GetOSMinorVersion(),
|
||||
GetOSMicroVersion(),
|
||||
major,
|
||||
minor,
|
||||
micro);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxPlatformInfo - string -> enum conversions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxOperatingSystemId wxPlatformInfo::GetOperatingSystemId(const wxString &str)
|
||||
{
|
||||
for ( size_t i = 0; i < WXSIZEOF(wxOperatingSystemIdNames); i++ )
|
||||
{
|
||||
if ( wxString(wxOperatingSystemIdNames[i]).CmpNoCase(str) == 0 )
|
||||
return (wxOperatingSystemId)(1 << i);
|
||||
}
|
||||
|
||||
return wxOS_UNKNOWN;
|
||||
}
|
||||
|
||||
wxPortId wxPlatformInfo::GetPortId(const wxString &str)
|
||||
{
|
||||
// recognize both short and long port names
|
||||
for ( size_t i = 0; i < WXSIZEOF(wxPortIdNames); i++ )
|
||||
{
|
||||
wxPortId current = (wxPortId)(1 << i);
|
||||
|
||||
if ( wxString(wxPortIdNames[i]).CmpNoCase(str) == 0 ||
|
||||
GetPortIdShortName(current, true).CmpNoCase(str) == 0 ||
|
||||
GetPortIdShortName(current, false).CmpNoCase(str) == 0 )
|
||||
return current;
|
||||
}
|
||||
|
||||
return wxPORT_UNKNOWN;
|
||||
}
|
||||
|
||||
wxArchitecture wxPlatformInfo::GetArch(const wxString &arch)
|
||||
{
|
||||
if ( arch.Contains(wxT("32")) )
|
||||
return wxARCH_32;
|
||||
|
||||
if ( arch.Contains(wxT("64")) )
|
||||
return wxARCH_64;
|
||||
|
||||
return wxARCH_INVALID;
|
||||
}
|
||||
|
||||
wxEndianness wxPlatformInfo::GetEndianness(const wxString& end)
|
||||
{
|
||||
const wxString endl(end.Lower());
|
||||
if ( endl.StartsWith(wxT("little")) )
|
||||
return wxENDIAN_LITTLE;
|
||||
|
||||
if ( endl.StartsWith(wxT("big")) )
|
||||
return wxENDIAN_BIG;
|
||||
|
||||
return wxENDIAN_INVALID;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/powercmn.cpp
|
||||
// Purpose: power event types and stubs for power functions
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 2006-05-27
|
||||
// Copyright: (c) 2006 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include "wx/power.h"
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
#ifdef wxHAS_POWER_EVENTS
|
||||
wxDEFINE_EVENT( wxEVT_POWER_SUSPENDING, wxPowerEvent );
|
||||
wxDEFINE_EVENT( wxEVT_POWER_SUSPENDED, wxPowerEvent );
|
||||
wxDEFINE_EVENT( wxEVT_POWER_SUSPEND_CANCEL, wxPowerEvent );
|
||||
wxDEFINE_EVENT( wxEVT_POWER_RESUME, wxPowerEvent );
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxPowerEvent, wxEvent);
|
||||
#endif
|
||||
|
||||
// Provide stubs for systems without power resource management functions
|
||||
#if !defined(__WINDOWS__) && !defined(__APPLE__)
|
||||
|
||||
bool
|
||||
wxPowerResource::Acquire(wxPowerResourceKind WXUNUSED(kind),
|
||||
const wxString& WXUNUSED(reason))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxPowerResource::Release(wxPowerResourceKind WXUNUSED(kind))
|
||||
{
|
||||
}
|
||||
|
||||
#endif // !(__WINDOWS__ || __APPLE__)
|
||||
|
||||
// provide stubs for the systems not implementing these functions
|
||||
#if !defined(__WINDOWS__)
|
||||
|
||||
wxPowerType wxGetPowerType()
|
||||
{
|
||||
return wxPOWER_UNKNOWN;
|
||||
}
|
||||
|
||||
wxBatteryState wxGetBatteryState()
|
||||
{
|
||||
return wxBATTERY_UNKNOWN_STATE;
|
||||
}
|
||||
|
||||
#endif // systems without power management functions
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/process.cpp
|
||||
// Purpose: Process termination classes
|
||||
// Author: Guilhem Lavaux
|
||||
// Modified by: Vadim Zeitlin to check error codes, added Detach() method
|
||||
// Created: 24/06/98
|
||||
// Copyright: (c) Guilhem Lavaux
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/process.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// event tables and such
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxDEFINE_EVENT( wxEVT_END_PROCESS, wxProcessEvent );
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxProcess, wxEvtHandler);
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent);
|
||||
|
||||
// ============================================================================
|
||||
// wxProcess implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxProcess creation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxProcess::Init(wxEvtHandler *parent, int id, int flags)
|
||||
{
|
||||
if ( parent )
|
||||
SetNextHandler(parent);
|
||||
|
||||
m_id = id;
|
||||
m_pid = 0;
|
||||
m_priority = wxPRIORITY_DEFAULT;
|
||||
m_redirect = (flags & wxPROCESS_REDIRECT) != 0;
|
||||
|
||||
#if wxUSE_STREAMS
|
||||
m_inputStream = NULL;
|
||||
m_errorStream = NULL;
|
||||
m_outputStream = NULL;
|
||||
#endif // wxUSE_STREAMS
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxProcess *wxProcess::Open(const wxString& cmd, int flags)
|
||||
{
|
||||
wxASSERT_MSG( !(flags & wxEXEC_SYNC), wxT("wxEXEC_SYNC should not be used." ));
|
||||
wxProcess *process = new wxProcess(wxPROCESS_REDIRECT);
|
||||
long pid = wxExecute(cmd, flags, process);
|
||||
if( !pid )
|
||||
{
|
||||
// couldn't launch the process
|
||||
delete process;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
process->SetPid(pid);
|
||||
|
||||
return process;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxProcess termination
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxProcess::~wxProcess()
|
||||
{
|
||||
#if wxUSE_STREAMS
|
||||
delete m_inputStream;
|
||||
delete m_errorStream;
|
||||
delete m_outputStream;
|
||||
#endif // wxUSE_STREAMS
|
||||
}
|
||||
|
||||
void wxProcess::OnTerminate(int pid, int status)
|
||||
{
|
||||
wxProcessEvent event(m_id, pid, status);
|
||||
|
||||
if ( !ProcessEvent(event) )
|
||||
delete this;
|
||||
//else: the object which processed the event is responsible for deleting
|
||||
// us!
|
||||
}
|
||||
|
||||
void wxProcess::Detach()
|
||||
{
|
||||
// we just detach from the next handler of the chain (i.e. our "parent" -- see ctor)
|
||||
// not also from the previous handler like wxEvtHandler::Unlink() would do:
|
||||
|
||||
if (m_nextHandler)
|
||||
m_nextHandler->SetPreviousHandler(m_previousHandler);
|
||||
|
||||
m_nextHandler = NULL;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// process IO redirection
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_STREAMS
|
||||
|
||||
void wxProcess::SetPipeStreams(wxInputStream *inputSstream,
|
||||
wxOutputStream *outputStream,
|
||||
wxInputStream *errorStream)
|
||||
{
|
||||
m_inputStream = inputSstream;
|
||||
m_errorStream = errorStream;
|
||||
m_outputStream = outputStream;
|
||||
}
|
||||
|
||||
bool wxProcess::IsInputOpened() const
|
||||
{
|
||||
return m_inputStream && m_inputStream->GetLastError() != wxSTREAM_EOF;
|
||||
}
|
||||
|
||||
bool wxProcess::IsInputAvailable() const
|
||||
{
|
||||
return m_inputStream && m_inputStream->CanRead();
|
||||
}
|
||||
|
||||
bool wxProcess::IsErrorAvailable() const
|
||||
{
|
||||
return m_errorStream && m_errorStream->CanRead();
|
||||
}
|
||||
|
||||
#endif // wxUSE_STREAMS
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// process killing
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/* static */
|
||||
wxKillError wxProcess::Kill(int pid, wxSignal sig, int flags)
|
||||
{
|
||||
wxKillError rc;
|
||||
(void)wxKill(pid, sig, &rc, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool wxProcess::Exists(int pid)
|
||||
{
|
||||
switch ( Kill(pid, wxSIGNONE) )
|
||||
{
|
||||
case wxKILL_OK:
|
||||
case wxKILL_ACCESS_DENIED:
|
||||
return true;
|
||||
|
||||
default:
|
||||
case wxKILL_ERROR:
|
||||
case wxKILL_BAD_SIGNAL:
|
||||
wxFAIL_MSG( wxT("unexpected wxProcess::Kill() return code") );
|
||||
wxFALLTHROUGH;
|
||||
|
||||
case wxKILL_NO_PROCESS:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool wxProcess::Activate() const
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
// This function is defined in src/msw/utils.cpp.
|
||||
extern bool wxMSWActivatePID(long pid);
|
||||
|
||||
return wxMSWActivatePID(m_pid);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void wxProcess::SetPriority(unsigned priority)
|
||||
{
|
||||
wxCHECK_RET( priority <= wxPRIORITY_MAX,
|
||||
wxS("Invalid process priority value.") );
|
||||
|
||||
m_priority = priority;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,715 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/regex.cpp
|
||||
// Purpose: regular expression matching
|
||||
// Author: Karsten Ballueder and Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 13.07.01
|
||||
// Copyright: (c) 2000 Karsten Ballueder <ballueder@gmx.net>
|
||||
// 2001 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_REGEX
|
||||
|
||||
#include "wx/regex.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/object.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/crt.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
// At least FreeBSD requires this.
|
||||
#if defined(__UNIX__)
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
// WXREGEX_USING_BUILTIN defined when using the built-in regex lib
|
||||
// WXREGEX_USING_RE_SEARCH defined when using re_search in the GNU regex lib
|
||||
// WXREGEX_IF_NEED_LEN() wrap the len parameter only used with the built-in
|
||||
// or GNU regex
|
||||
// WXREGEX_CONVERT_TO_MB defined when the regex lib is using chars and
|
||||
// wxChar is wide, so conversion must be done
|
||||
// WXREGEX_CHAR(x) Convert wxChar to wxRegChar
|
||||
//
|
||||
#ifdef __REG_NOFRONT
|
||||
# define WXREGEX_USING_BUILTIN
|
||||
# define WXREGEX_IF_NEED_LEN(x) ,x
|
||||
# if wxUSE_UNICODE
|
||||
# define WXREGEX_CHAR(x) (x).wc_str()
|
||||
# else
|
||||
# define WXREGEX_CHAR(x) (x).mb_str()
|
||||
# endif
|
||||
#else
|
||||
# ifdef HAVE_RE_SEARCH
|
||||
# define WXREGEX_IF_NEED_LEN(x) ,x
|
||||
# define WXREGEX_USING_RE_SEARCH
|
||||
# else
|
||||
# define WXREGEX_IF_NEED_LEN(x)
|
||||
# endif
|
||||
# if wxUSE_UNICODE
|
||||
# define WXREGEX_CONVERT_TO_MB
|
||||
# endif
|
||||
# define WXREGEX_CHAR(x) (x).mb_str()
|
||||
# define wx_regfree regfree
|
||||
# define wx_regerror regerror
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// private classes
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef WXREGEX_USING_RE_SEARCH
|
||||
|
||||
// the array of offsets for the matches, the usual POSIX regmatch_t array.
|
||||
class wxRegExMatches
|
||||
{
|
||||
public:
|
||||
typedef regmatch_t *match_type;
|
||||
|
||||
wxRegExMatches(size_t n) { m_matches = new regmatch_t[n]; }
|
||||
~wxRegExMatches() { delete [] m_matches; }
|
||||
|
||||
// we just use casts here because the fields of regmatch_t struct may be 64
|
||||
// bit but we're limited to size_t in our public API and are not going to
|
||||
// change it because operating on strings longer than 4GB using it is
|
||||
// absolutely impractical anyhow
|
||||
size_t Start(size_t n) const
|
||||
{
|
||||
return wx_truncate_cast(size_t, m_matches[n].rm_so);
|
||||
}
|
||||
|
||||
size_t End(size_t n) const
|
||||
{
|
||||
return wx_truncate_cast(size_t, m_matches[n].rm_eo);
|
||||
}
|
||||
|
||||
regmatch_t *get() const { return m_matches; }
|
||||
|
||||
private:
|
||||
regmatch_t *m_matches;
|
||||
};
|
||||
|
||||
#else // WXREGEX_USING_RE_SEARCH
|
||||
|
||||
// the array of offsets for the matches, the struct used by the GNU lib
|
||||
class wxRegExMatches
|
||||
{
|
||||
public:
|
||||
typedef re_registers *match_type;
|
||||
|
||||
wxRegExMatches(size_t n)
|
||||
{
|
||||
m_matches.num_regs = n;
|
||||
m_matches.start = new regoff_t[n];
|
||||
m_matches.end = new regoff_t[n];
|
||||
}
|
||||
|
||||
~wxRegExMatches()
|
||||
{
|
||||
delete [] m_matches.start;
|
||||
delete [] m_matches.end;
|
||||
}
|
||||
|
||||
size_t Start(size_t n) const { return m_matches.start[n]; }
|
||||
size_t End(size_t n) const { return m_matches.end[n]; }
|
||||
|
||||
re_registers *get() { return &m_matches; }
|
||||
|
||||
private:
|
||||
re_registers m_matches;
|
||||
};
|
||||
|
||||
#endif // WXREGEX_USING_RE_SEARCH
|
||||
|
||||
// the character type used by the regular expression engine
|
||||
#ifndef WXREGEX_CONVERT_TO_MB
|
||||
typedef wxChar wxRegChar;
|
||||
#else
|
||||
typedef char wxRegChar;
|
||||
#endif
|
||||
|
||||
// the real implementation of wxRegEx
|
||||
class wxRegExImpl
|
||||
{
|
||||
public:
|
||||
// ctor and dtor
|
||||
wxRegExImpl();
|
||||
~wxRegExImpl();
|
||||
|
||||
// return true if Compile() had been called successfully
|
||||
bool IsValid() const { return m_isCompiled; }
|
||||
|
||||
// RE operations
|
||||
bool Compile(const wxString& expr, int flags = 0);
|
||||
bool Matches(const wxRegChar *str, int flags
|
||||
WXREGEX_IF_NEED_LEN(size_t len)) const;
|
||||
bool GetMatch(size_t *start, size_t *len, size_t index = 0) const;
|
||||
size_t GetMatchCount() const;
|
||||
int Replace(wxString *pattern, const wxString& replacement,
|
||||
size_t maxMatches = 0) const;
|
||||
|
||||
private:
|
||||
// return the string containing the error message for the given err code
|
||||
wxString GetErrorMsg(int errorcode, bool badconv) const;
|
||||
|
||||
// init the members
|
||||
void Init()
|
||||
{
|
||||
m_isCompiled = false;
|
||||
m_Matches = NULL;
|
||||
m_nMatches = 0;
|
||||
}
|
||||
|
||||
// free the RE if compiled
|
||||
void Free()
|
||||
{
|
||||
if ( IsValid() )
|
||||
{
|
||||
wx_regfree(&m_RegEx);
|
||||
}
|
||||
|
||||
delete m_Matches;
|
||||
}
|
||||
|
||||
// free the RE if any and reinit the members
|
||||
void Reinit()
|
||||
{
|
||||
Free();
|
||||
Init();
|
||||
}
|
||||
|
||||
// compiled RE
|
||||
regex_t m_RegEx;
|
||||
|
||||
// the subexpressions data
|
||||
wxRegExMatches *m_Matches;
|
||||
size_t m_nMatches;
|
||||
|
||||
// true if m_RegEx is valid
|
||||
bool m_isCompiled;
|
||||
};
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxRegExImpl
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxRegExImpl::wxRegExImpl()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
wxRegExImpl::~wxRegExImpl()
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
wxString wxRegExImpl::GetErrorMsg(int errorcode, bool badconv) const
|
||||
{
|
||||
#ifdef WXREGEX_CONVERT_TO_MB
|
||||
// currently only needed when using system library in Unicode mode
|
||||
if ( badconv )
|
||||
{
|
||||
return _("conversion to 8-bit encoding failed");
|
||||
}
|
||||
#else
|
||||
// 'use' badconv to avoid a compiler warning
|
||||
(void)badconv;
|
||||
#endif
|
||||
|
||||
wxString szError;
|
||||
|
||||
// first get the string length needed
|
||||
int len = wx_regerror(errorcode, &m_RegEx, NULL, 0);
|
||||
if ( len > 0 )
|
||||
{
|
||||
char* szcmbError = new char[++len];
|
||||
|
||||
(void)wx_regerror(errorcode, &m_RegEx, szcmbError, len);
|
||||
|
||||
szError = wxConvLibc.cMB2WX(szcmbError);
|
||||
delete [] szcmbError;
|
||||
}
|
||||
else // regerror() returned 0
|
||||
{
|
||||
szError = _("unknown error");
|
||||
}
|
||||
|
||||
return szError;
|
||||
}
|
||||
|
||||
bool wxRegExImpl::Compile(const wxString& expr, int flags)
|
||||
{
|
||||
Reinit();
|
||||
|
||||
#ifdef WX_NO_REGEX_ADVANCED
|
||||
# define FLAVORS wxRE_BASIC
|
||||
#else
|
||||
# define FLAVORS (wxRE_ADVANCED | wxRE_BASIC)
|
||||
wxASSERT_MSG( (flags & FLAVORS) != FLAVORS,
|
||||
wxT("incompatible flags in wxRegEx::Compile") );
|
||||
#endif
|
||||
wxASSERT_MSG( !(flags & ~(FLAVORS | wxRE_ICASE | wxRE_NOSUB | wxRE_NEWLINE)),
|
||||
wxT("unrecognized flags in wxRegEx::Compile") );
|
||||
|
||||
// translate our flags to regcomp() ones
|
||||
int flagsRE = 0;
|
||||
if ( !(flags & wxRE_BASIC) )
|
||||
{
|
||||
#ifndef WX_NO_REGEX_ADVANCED
|
||||
if (flags & wxRE_ADVANCED)
|
||||
flagsRE |= REG_ADVANCED;
|
||||
else
|
||||
#endif
|
||||
flagsRE |= REG_EXTENDED;
|
||||
}
|
||||
if ( flags & wxRE_ICASE )
|
||||
flagsRE |= REG_ICASE;
|
||||
if ( flags & wxRE_NOSUB )
|
||||
flagsRE |= REG_NOSUB;
|
||||
if ( flags & wxRE_NEWLINE )
|
||||
flagsRE |= REG_NEWLINE;
|
||||
|
||||
// compile it
|
||||
#ifdef WXREGEX_USING_BUILTIN
|
||||
bool conv = true;
|
||||
// FIXME-UTF8: use wc_str() after removing ANSI build
|
||||
int errorcode = wx_re_comp(&m_RegEx, expr.c_str(), expr.length(), flagsRE);
|
||||
#else
|
||||
// FIXME-UTF8: this is potentially broken, we shouldn't even try it
|
||||
// and should always use builtin regex library (or PCRE?)
|
||||
const wxWX2MBbuf conv = expr.mbc_str();
|
||||
int errorcode = conv ? regcomp(&m_RegEx, conv, flagsRE) : REG_BADPAT;
|
||||
#endif
|
||||
|
||||
if ( errorcode )
|
||||
{
|
||||
wxLogError(_("Invalid regular expression '%s': %s"),
|
||||
expr.c_str(), GetErrorMsg(errorcode, !conv).c_str());
|
||||
|
||||
m_isCompiled = false;
|
||||
}
|
||||
else // ok
|
||||
{
|
||||
// don't allocate the matches array now, but do it later if necessary
|
||||
if ( flags & wxRE_NOSUB )
|
||||
{
|
||||
// we don't need it at all
|
||||
m_nMatches = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we will alloc the array later (only if really needed) but count
|
||||
// the number of sub-expressions in the regex right now
|
||||
|
||||
// there is always one for the whole expression
|
||||
m_nMatches = 1;
|
||||
|
||||
// and some more for bracketed subexperessions
|
||||
for ( const wxChar *cptr = expr.c_str(); *cptr; cptr++ )
|
||||
{
|
||||
if ( *cptr == wxT('\\') )
|
||||
{
|
||||
// in basic RE syntax groups are inside \(...\)
|
||||
if ( *++cptr == wxT('(') && (flags & wxRE_BASIC) )
|
||||
{
|
||||
m_nMatches++;
|
||||
}
|
||||
}
|
||||
else if ( *cptr == wxT('(') && !(flags & wxRE_BASIC) )
|
||||
{
|
||||
// we know that the previous character is not an unquoted
|
||||
// backslash because it would have been eaten above, so we
|
||||
// have a bare '(' and this indicates a group start for the
|
||||
// extended syntax. '(?' is used for extensions by perl-
|
||||
// like REs (e.g. advanced), and is not valid for POSIX
|
||||
// extended, so ignore them always.
|
||||
if ( cptr[1] != wxT('?') )
|
||||
m_nMatches++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_isCompiled = true;
|
||||
}
|
||||
|
||||
return IsValid();
|
||||
}
|
||||
|
||||
#ifdef WXREGEX_USING_RE_SEARCH
|
||||
|
||||
// On GNU, regexec is implemented as a wrapper around re_search. re_search
|
||||
// requires a length parameter which the POSIX regexec does not have,
|
||||
// therefore regexec must do a strlen on the search text each time it is
|
||||
// called. This can drastically affect performance when matching is done in
|
||||
// a loop along a string, such as during a search and replace. Therefore if
|
||||
// re_search is detected by configure, it is used directly.
|
||||
//
|
||||
static int ReSearch(const regex_t *preg,
|
||||
const char *text,
|
||||
size_t len,
|
||||
re_registers *matches,
|
||||
int eflags)
|
||||
{
|
||||
regex_t *pattern = const_cast<regex_t*>(preg);
|
||||
|
||||
pattern->not_bol = (eflags & REG_NOTBOL) != 0;
|
||||
pattern->not_eol = (eflags & REG_NOTEOL) != 0;
|
||||
pattern->regs_allocated = REGS_FIXED;
|
||||
|
||||
int ret = re_search(pattern, text, len, 0, len, matches);
|
||||
return ret >= 0 ? 0 : REG_NOMATCH;
|
||||
}
|
||||
|
||||
#endif // WXREGEX_USING_RE_SEARCH
|
||||
|
||||
bool wxRegExImpl::Matches(const wxRegChar *str,
|
||||
int flags
|
||||
WXREGEX_IF_NEED_LEN(size_t len)) const
|
||||
{
|
||||
wxCHECK_MSG( IsValid(), false, wxT("must successfully Compile() first") );
|
||||
|
||||
// translate our flags to regexec() ones
|
||||
wxASSERT_MSG( !(flags & ~(wxRE_NOTBOL | wxRE_NOTEOL)),
|
||||
wxT("unrecognized flags in wxRegEx::Matches") );
|
||||
|
||||
int flagsRE = 0;
|
||||
if ( flags & wxRE_NOTBOL )
|
||||
flagsRE |= REG_NOTBOL;
|
||||
if ( flags & wxRE_NOTEOL )
|
||||
flagsRE |= REG_NOTEOL;
|
||||
|
||||
// allocate matches array if needed
|
||||
wxRegExImpl *self = wxConstCast(this, wxRegExImpl);
|
||||
if ( !m_Matches && m_nMatches )
|
||||
{
|
||||
self->m_Matches = new wxRegExMatches(m_nMatches);
|
||||
}
|
||||
|
||||
wxRegExMatches::match_type matches = m_Matches ? m_Matches->get() : NULL;
|
||||
|
||||
// do match it
|
||||
#if defined WXREGEX_USING_BUILTIN
|
||||
int rc = wx_re_exec(&self->m_RegEx, str, len, NULL, m_nMatches, matches, flagsRE);
|
||||
#elif defined WXREGEX_USING_RE_SEARCH
|
||||
int rc = str ? ReSearch(&self->m_RegEx, str, len, matches, flagsRE) : REG_BADPAT;
|
||||
#else
|
||||
int rc = str ? regexec(&self->m_RegEx, str, m_nMatches, matches, flagsRE) : REG_BADPAT;
|
||||
#endif
|
||||
|
||||
switch ( rc )
|
||||
{
|
||||
case 0:
|
||||
// matched successfully
|
||||
return true;
|
||||
|
||||
default:
|
||||
// an error occurred
|
||||
wxLogError(_("Failed to find match for regular expression: %s"),
|
||||
GetErrorMsg(rc, !str).c_str());
|
||||
wxFALLTHROUGH;
|
||||
|
||||
case REG_NOMATCH:
|
||||
// no match
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool wxRegExImpl::GetMatch(size_t *start, size_t *len, size_t index) const
|
||||
{
|
||||
wxCHECK_MSG( IsValid(), false, wxT("must successfully Compile() first") );
|
||||
wxCHECK_MSG( m_nMatches, false, wxT("can't use with wxRE_NOSUB") );
|
||||
wxCHECK_MSG( m_Matches, false, wxT("must call Matches() first") );
|
||||
wxCHECK_MSG( index < m_nMatches, false, wxT("invalid match index") );
|
||||
|
||||
if ( start )
|
||||
*start = m_Matches->Start(index);
|
||||
if ( len )
|
||||
*len = m_Matches->End(index) - m_Matches->Start(index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t wxRegExImpl::GetMatchCount() const
|
||||
{
|
||||
wxCHECK_MSG( IsValid(), 0, wxT("must successfully Compile() first") );
|
||||
wxCHECK_MSG( m_nMatches, 0, wxT("can't use with wxRE_NOSUB") );
|
||||
|
||||
return m_nMatches;
|
||||
}
|
||||
|
||||
int wxRegExImpl::Replace(wxString *text,
|
||||
const wxString& replacement,
|
||||
size_t maxMatches) const
|
||||
{
|
||||
wxCHECK_MSG( text, wxNOT_FOUND, wxT("NULL text in wxRegEx::Replace") );
|
||||
wxCHECK_MSG( IsValid(), wxNOT_FOUND, wxT("must successfully Compile() first") );
|
||||
|
||||
// the input string
|
||||
#ifndef WXREGEX_CONVERT_TO_MB
|
||||
const wxChar *textstr = text->c_str();
|
||||
size_t textlen = text->length();
|
||||
#else
|
||||
const wxWX2MBbuf textstr = WXREGEX_CHAR(*text);
|
||||
if (!textstr)
|
||||
{
|
||||
wxLogError(_("Failed to find match for regular expression: %s"),
|
||||
GetErrorMsg(0, true).c_str());
|
||||
return 0;
|
||||
}
|
||||
size_t textlen = strlen(textstr);
|
||||
text->clear();
|
||||
#endif
|
||||
|
||||
// the replacement text
|
||||
wxString textNew;
|
||||
|
||||
// the result, allow 25% extra
|
||||
wxString result;
|
||||
result.reserve(5 * textlen / 4);
|
||||
|
||||
// attempt at optimization: don't iterate over the string if it doesn't
|
||||
// contain back references at all
|
||||
bool mayHaveBackrefs =
|
||||
replacement.find_first_of(wxT("\\&")) != wxString::npos;
|
||||
|
||||
if ( !mayHaveBackrefs )
|
||||
{
|
||||
textNew = replacement;
|
||||
}
|
||||
|
||||
// the position where we start looking for the match
|
||||
size_t matchStart = 0;
|
||||
|
||||
// number of replacement made: we won't make more than maxMatches of them
|
||||
// (unless maxMatches is 0 which doesn't limit the number of replacements)
|
||||
size_t countRepl = 0;
|
||||
|
||||
// note that "^" shouldn't match after the first call to Matches() so we
|
||||
// use wxRE_NOTBOL to prevent it from happening
|
||||
while ( (!maxMatches || countRepl < maxMatches) &&
|
||||
Matches(
|
||||
#ifndef WXREGEX_CONVERT_TO_MB
|
||||
textstr + matchStart,
|
||||
#else
|
||||
textstr.data() + matchStart,
|
||||
#endif
|
||||
countRepl ? wxRE_NOTBOL : 0
|
||||
WXREGEX_IF_NEED_LEN(textlen - matchStart)) )
|
||||
{
|
||||
// the string possibly contains back references: we need to calculate
|
||||
// the replacement text anew after each match
|
||||
if ( mayHaveBackrefs )
|
||||
{
|
||||
mayHaveBackrefs = false;
|
||||
textNew.clear();
|
||||
textNew.reserve(replacement.length());
|
||||
|
||||
for ( const wxChar *p = replacement.c_str(); *p; p++ )
|
||||
{
|
||||
size_t index = (size_t)-1;
|
||||
|
||||
if ( *p == wxT('\\') )
|
||||
{
|
||||
if ( wxIsdigit(*++p) )
|
||||
{
|
||||
// back reference
|
||||
wxChar *end;
|
||||
index = (size_t)wxStrtoul(p, &end, 10);
|
||||
p = end - 1; // -1 to compensate for p++ in the loop
|
||||
}
|
||||
//else: backslash used as escape character
|
||||
}
|
||||
else if ( *p == wxT('&') )
|
||||
{
|
||||
// treat this as "\0" for compatbility with ed and such
|
||||
index = 0;
|
||||
}
|
||||
|
||||
// do we have a back reference?
|
||||
if ( index != (size_t)-1 )
|
||||
{
|
||||
// yes, get its text
|
||||
size_t start, len;
|
||||
if ( !GetMatch(&start, &len, index) )
|
||||
{
|
||||
wxFAIL_MSG( wxT("invalid back reference") );
|
||||
|
||||
// just eat it...
|
||||
}
|
||||
else
|
||||
{
|
||||
textNew += wxString(
|
||||
#ifndef WXREGEX_CONVERT_TO_MB
|
||||
textstr
|
||||
#else
|
||||
textstr.data()
|
||||
#endif
|
||||
+ matchStart + start,
|
||||
*wxConvCurrent, len);
|
||||
|
||||
mayHaveBackrefs = true;
|
||||
}
|
||||
}
|
||||
else // ordinary character
|
||||
{
|
||||
textNew += *p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t start, len;
|
||||
if ( !GetMatch(&start, &len) )
|
||||
{
|
||||
// we did have match as Matches() returned true above!
|
||||
wxFAIL_MSG( wxT("internal logic error in wxRegEx::Replace") );
|
||||
|
||||
return wxNOT_FOUND;
|
||||
}
|
||||
|
||||
// an insurance against implementations that don't grow exponentially
|
||||
// to ensure building the result takes linear time
|
||||
if (result.capacity() < result.length() + start + textNew.length())
|
||||
result.reserve(2 * result.length());
|
||||
|
||||
#ifndef WXREGEX_CONVERT_TO_MB
|
||||
result.append(*text, matchStart, start);
|
||||
#else
|
||||
result.append(wxString(textstr.data() + matchStart, *wxConvCurrent, start));
|
||||
#endif
|
||||
matchStart += start;
|
||||
result.append(textNew);
|
||||
|
||||
countRepl++;
|
||||
|
||||
matchStart += len;
|
||||
}
|
||||
|
||||
#ifndef WXREGEX_CONVERT_TO_MB
|
||||
result.append(*text, matchStart, wxString::npos);
|
||||
#else
|
||||
result.append(wxString(textstr.data() + matchStart, *wxConvCurrent));
|
||||
#endif
|
||||
*text = result;
|
||||
|
||||
return countRepl;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxRegEx: all methods are mostly forwarded to wxRegExImpl
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxRegEx::Init()
|
||||
{
|
||||
m_impl = NULL;
|
||||
}
|
||||
|
||||
wxRegEx::~wxRegEx()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
bool wxRegEx::Compile(const wxString& expr, int flags)
|
||||
{
|
||||
if ( !m_impl )
|
||||
{
|
||||
m_impl = new wxRegExImpl;
|
||||
}
|
||||
|
||||
if ( !m_impl->Compile(expr, flags) )
|
||||
{
|
||||
// error message already given in wxRegExImpl::Compile
|
||||
wxDELETE(m_impl);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxRegEx::Matches(const wxString& str, int flags) const
|
||||
{
|
||||
wxCHECK_MSG( IsValid(), false, wxT("must successfully Compile() first") );
|
||||
|
||||
return m_impl->Matches(WXREGEX_CHAR(str), flags
|
||||
WXREGEX_IF_NEED_LEN(str.length()));
|
||||
}
|
||||
|
||||
bool wxRegEx::GetMatch(size_t *start, size_t *len, size_t index) const
|
||||
{
|
||||
wxCHECK_MSG( IsValid(), false, wxT("must successfully Compile() first") );
|
||||
|
||||
return m_impl->GetMatch(start, len, index);
|
||||
}
|
||||
|
||||
wxString wxRegEx::GetMatch(const wxString& text, size_t index) const
|
||||
{
|
||||
size_t start, len;
|
||||
if ( !GetMatch(&start, &len, index) )
|
||||
return wxEmptyString;
|
||||
|
||||
return text.Mid(start, len);
|
||||
}
|
||||
|
||||
size_t wxRegEx::GetMatchCount() const
|
||||
{
|
||||
wxCHECK_MSG( IsValid(), 0, wxT("must successfully Compile() first") );
|
||||
|
||||
return m_impl->GetMatchCount();
|
||||
}
|
||||
|
||||
int wxRegEx::Replace(wxString *pattern,
|
||||
const wxString& replacement,
|
||||
size_t maxMatches) const
|
||||
{
|
||||
wxCHECK_MSG( IsValid(), wxNOT_FOUND, wxT("must successfully Compile() first") );
|
||||
|
||||
return m_impl->Replace(pattern, replacement, maxMatches);
|
||||
}
|
||||
|
||||
wxString wxRegEx::QuoteMeta(const wxString& str)
|
||||
{
|
||||
static const wxString s_strMetaChars = wxS("\\^$.|?*+()[]{}");
|
||||
|
||||
wxString strEscaped;
|
||||
|
||||
// This is the maximal possible length of the resulting string, if every
|
||||
// character were escaped.
|
||||
strEscaped.reserve(str.length() * 2);
|
||||
|
||||
for ( wxString::const_iterator it = str.begin(); it != str.end(); ++it )
|
||||
{
|
||||
if ( s_strMetaChars.find(*it) != wxString::npos )
|
||||
{
|
||||
strEscaped += wxS('\\');
|
||||
}
|
||||
|
||||
strEscaped += *it;
|
||||
}
|
||||
|
||||
strEscaped.shrink_to_fit();
|
||||
|
||||
return strEscaped;
|
||||
}
|
||||
|
||||
#endif // wxUSE_REGEX
|
||||
@@ -0,0 +1,267 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/selectdispatcher.cpp
|
||||
// Purpose: implements dispatcher for select() call
|
||||
// Author: Lukasz Michalski and Vadim Zeitlin
|
||||
// Created: December 2006
|
||||
// Copyright: (c) 2006 Lukasz Michalski
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_SELECT_DISPATCHER
|
||||
|
||||
#include "wx/private/selectdispatcher.h"
|
||||
#include "wx/unix/private.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/hash.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/intl.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define wxSelectDispatcher_Trace wxT("selectdispatcher")
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxSelectSets
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int wxSelectSets::ms_flags[wxSelectSets::Max] =
|
||||
{
|
||||
wxFDIO_INPUT,
|
||||
wxFDIO_OUTPUT,
|
||||
wxFDIO_EXCEPTION,
|
||||
};
|
||||
|
||||
const char *wxSelectSets::ms_names[wxSelectSets::Max] =
|
||||
{
|
||||
"input",
|
||||
"output",
|
||||
"exceptional",
|
||||
};
|
||||
|
||||
wxSelectSets::Callback wxSelectSets::ms_handlers[wxSelectSets::Max] =
|
||||
{
|
||||
&wxFDIOHandler::OnReadWaiting,
|
||||
&wxFDIOHandler::OnWriteWaiting,
|
||||
&wxFDIOHandler::OnExceptionWaiting,
|
||||
};
|
||||
|
||||
wxSelectSets::wxSelectSets()
|
||||
{
|
||||
for ( int n = 0; n < Max; n++ )
|
||||
{
|
||||
wxFD_ZERO(&m_fds[n]);
|
||||
}
|
||||
}
|
||||
|
||||
bool wxSelectSets::HasFD(int fd) const
|
||||
{
|
||||
for ( int n = 0; n < Max; n++ )
|
||||
{
|
||||
if ( wxFD_ISSET(fd, const_cast<fd_set*>(&m_fds[n])) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wxSelectSets::SetFD(int fd, int flags)
|
||||
{
|
||||
wxCHECK_MSG( fd >= 0, false, wxT("invalid descriptor") );
|
||||
|
||||
for ( int n = 0; n < Max; n++ )
|
||||
{
|
||||
if ( flags & ms_flags[n] )
|
||||
{
|
||||
wxFD_SET(fd, &m_fds[n]);
|
||||
}
|
||||
else if ( wxFD_ISSET(fd, (fd_set*) &m_fds[n]) )
|
||||
{
|
||||
wxFD_CLR(fd, &m_fds[n]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int wxSelectSets::Select(int nfds, struct timeval *tv)
|
||||
{
|
||||
return select(nfds, &m_fds[Read], &m_fds[Write], &m_fds[Except], tv);
|
||||
}
|
||||
|
||||
bool wxSelectSets::Handle(int fd, wxFDIOHandler& handler) const
|
||||
{
|
||||
for ( int n = 0; n < Max; n++ )
|
||||
{
|
||||
if ( wxFD_ISSET(fd, const_cast<fd_set*>(&m_fds[n])) )
|
||||
{
|
||||
wxLogTrace(wxSelectDispatcher_Trace,
|
||||
wxT("Got %s event on fd %d"), ms_names[n], fd);
|
||||
(handler.*ms_handlers[n])();
|
||||
// callback can modify sets and destroy handler
|
||||
// this forces that one event can be processed at one time
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxSelectDispatcher
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxSelectDispatcher::RegisterFD(int fd, wxFDIOHandler *handler, int flags)
|
||||
{
|
||||
wxCRIT_SECT_LOCKER(lock, m_cs);
|
||||
|
||||
if ( !wxMappedFDIODispatcher::RegisterFD(fd, handler, flags) )
|
||||
return false;
|
||||
|
||||
if ( !m_sets.SetFD(fd, flags) )
|
||||
return false;
|
||||
|
||||
if ( fd > m_maxFD )
|
||||
m_maxFD = fd;
|
||||
|
||||
wxLogTrace(wxSelectDispatcher_Trace,
|
||||
wxT("Registered fd %d: input:%d, output:%d, exceptional:%d"), fd, (flags & wxFDIO_INPUT) == wxFDIO_INPUT, (flags & wxFDIO_OUTPUT), (flags & wxFDIO_EXCEPTION) == wxFDIO_EXCEPTION);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxSelectDispatcher::ModifyFD(int fd, wxFDIOHandler *handler, int flags)
|
||||
{
|
||||
wxCRIT_SECT_LOCKER(lock, m_cs);
|
||||
|
||||
if ( !wxMappedFDIODispatcher::ModifyFD(fd, handler, flags) )
|
||||
return false;
|
||||
|
||||
wxASSERT_MSG( fd <= m_maxFD, wxT("logic error: registered fd > m_maxFD?") );
|
||||
|
||||
wxLogTrace(wxSelectDispatcher_Trace,
|
||||
wxT("Modified fd %d: input:%d, output:%d, exceptional:%d"), fd, (flags & wxFDIO_INPUT) == wxFDIO_INPUT, (flags & wxFDIO_OUTPUT) == wxFDIO_OUTPUT, (flags & wxFDIO_EXCEPTION) == wxFDIO_EXCEPTION);
|
||||
return m_sets.SetFD(fd, flags);
|
||||
}
|
||||
|
||||
bool wxSelectDispatcher::UnregisterFD(int fd)
|
||||
{
|
||||
wxCRIT_SECT_LOCKER(lock, m_cs);
|
||||
|
||||
m_sets.ClearFD(fd);
|
||||
|
||||
if ( !wxMappedFDIODispatcher::UnregisterFD(fd) )
|
||||
return false;
|
||||
|
||||
// remove the handler if we don't need it any more
|
||||
if ( !m_sets.HasFD(fd) )
|
||||
{
|
||||
if ( fd == m_maxFD )
|
||||
{
|
||||
// need to find new max fd
|
||||
m_maxFD = -1;
|
||||
for ( wxFDIOHandlerMap::const_iterator it = m_handlers.begin();
|
||||
it != m_handlers.end();
|
||||
++it )
|
||||
{
|
||||
if ( it->first > m_maxFD )
|
||||
{
|
||||
m_maxFD = it->first;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxLogTrace(wxSelectDispatcher_Trace,
|
||||
wxT("Removed fd %d, current max: %d"), fd, m_maxFD);
|
||||
return true;
|
||||
}
|
||||
|
||||
int wxSelectDispatcher::ProcessSets(const wxSelectSets& sets)
|
||||
{
|
||||
int numEvents = 0;
|
||||
for ( int fd = 0; fd <= m_maxFD; fd++ )
|
||||
{
|
||||
if ( !sets.HasFD(fd) )
|
||||
continue;
|
||||
|
||||
wxFDIOHandler * const handler = FindHandler(fd);
|
||||
if ( !handler )
|
||||
{
|
||||
wxFAIL_MSG( wxT("NULL handler in wxSelectDispatcher?") );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( sets.Handle(fd, *handler) )
|
||||
numEvents++;
|
||||
}
|
||||
|
||||
return numEvents;
|
||||
}
|
||||
|
||||
int wxSelectDispatcher::DoSelect(wxSelectSets& sets, int timeout) const
|
||||
{
|
||||
struct timeval tv,
|
||||
*ptv;
|
||||
if ( timeout != TIMEOUT_INFINITE )
|
||||
{
|
||||
ptv = &tv;
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout % 1000)*1000;
|
||||
}
|
||||
else // no timeout
|
||||
{
|
||||
ptv = NULL;
|
||||
}
|
||||
|
||||
int ret = sets.Select(m_maxFD + 1, ptv);
|
||||
|
||||
// TODO: we need to restart select() in this case but for now just return
|
||||
// as if timeout expired
|
||||
if ( ret == -1 && errno == EINTR )
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool wxSelectDispatcher::HasPending() const
|
||||
{
|
||||
wxSelectSets sets(m_sets);
|
||||
return DoSelect(sets, 0) > 0;
|
||||
}
|
||||
|
||||
int wxSelectDispatcher::Dispatch(int timeout)
|
||||
{
|
||||
wxSelectSets sets(m_sets);
|
||||
switch ( DoSelect(sets, timeout) )
|
||||
{
|
||||
case -1:
|
||||
wxLogSysError(_("Failed to monitor I/O channels"));
|
||||
return -1;
|
||||
|
||||
case 0:
|
||||
// timeout expired without anything happening
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return ProcessSets(sets);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_SELECT_DISPATCHER
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,127 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/socketiohandler.cpp
|
||||
// Purpose: implementation of wxFDIOHandler for wxSocket
|
||||
// Author: Angel Vidal, Lukasz Michalski
|
||||
// Created: 08.24.06
|
||||
// Copyright: (c) 2006 Angel vidal
|
||||
// (c) 2007 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_SOCKETS
|
||||
|
||||
#include "wx/app.h"
|
||||
#include "wx/apptrait.h"
|
||||
#include "wx/private/socket.h"
|
||||
#include "wx/link.h"
|
||||
|
||||
// ============================================================================
|
||||
// wxSocketFDBasedManager implementation
|
||||
// ============================================================================
|
||||
|
||||
bool wxSocketFDBasedManager::OnInit()
|
||||
{
|
||||
wxAppTraits * const traits = wxApp::GetTraitsIfExists();
|
||||
if ( !traits )
|
||||
return false;
|
||||
|
||||
m_fdioManager = traits->GetFDIOManager();
|
||||
return m_fdioManager != NULL;
|
||||
}
|
||||
|
||||
void wxSocketFDBasedManager::Install_Callback(wxSocketImpl *socket_,
|
||||
wxSocketNotify event)
|
||||
{
|
||||
wxSocketImplUnix * const
|
||||
socket = static_cast<wxSocketImplUnix *>(socket_);
|
||||
|
||||
wxCHECK_RET( socket->m_fd != -1,
|
||||
"shouldn't be called on invalid socket" );
|
||||
|
||||
const wxFDIOManager::Direction d = GetDirForEvent(socket, event);
|
||||
|
||||
int& fd = FD(socket, d);
|
||||
if ( fd != -1 )
|
||||
m_fdioManager->RemoveInput(socket, fd, d);
|
||||
|
||||
fd = m_fdioManager->AddInput(socket, socket->m_fd, d);
|
||||
}
|
||||
|
||||
void wxSocketFDBasedManager::Uninstall_Callback(wxSocketImpl *socket_,
|
||||
wxSocketNotify event)
|
||||
{
|
||||
wxSocketImplUnix * const
|
||||
socket = static_cast<wxSocketImplUnix *>(socket_);
|
||||
|
||||
const wxFDIOManager::Direction d = GetDirForEvent(socket, event);
|
||||
|
||||
int& fd = FD(socket, d);
|
||||
if ( fd != -1 )
|
||||
{
|
||||
m_fdioManager->RemoveInput(socket, fd, d);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
wxFDIOManager::Direction
|
||||
wxSocketFDBasedManager::GetDirForEvent(wxSocketImpl *socket,
|
||||
wxSocketNotify event)
|
||||
{
|
||||
switch ( event )
|
||||
{
|
||||
default:
|
||||
wxFAIL_MSG( "unknown socket event" );
|
||||
return wxFDIOManager::INPUT; // we must return something
|
||||
|
||||
case wxSOCKET_LOST:
|
||||
wxFAIL_MSG( "unexpected socket event" );
|
||||
return wxFDIOManager::INPUT; // as above
|
||||
|
||||
case wxSOCKET_INPUT:
|
||||
return wxFDIOManager::INPUT;
|
||||
|
||||
case wxSOCKET_OUTPUT:
|
||||
return wxFDIOManager::OUTPUT;
|
||||
|
||||
case wxSOCKET_CONNECTION:
|
||||
// for server sockets we're interested in events indicating
|
||||
// that a new connection is pending, i.e. that accept() will
|
||||
// succeed and this is indicated by socket becoming ready for
|
||||
// reading, while for the other ones we're interested in the
|
||||
// completion of non-blocking connect() which is indicated by
|
||||
// the socket becoming ready for writing
|
||||
return socket->IsServer() ? wxFDIOManager::INPUT
|
||||
: wxFDIOManager::OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
// set the wxBase variable to point to our wxSocketManager implementation
|
||||
//
|
||||
// see comments in wx/apptrait.h for the explanation of why do we do it
|
||||
// like this
|
||||
static struct ManagerSetter
|
||||
{
|
||||
ManagerSetter()
|
||||
{
|
||||
static wxSocketFDBasedManager s_manager;
|
||||
wxAppTraits::SetDefaultSocketManager(&s_manager);
|
||||
}
|
||||
} gs_managerSetter;
|
||||
|
||||
|
||||
// see the relative linker macro in socket.cpp
|
||||
wxFORCE_LINK_THIS_MODULE( socketiohandler );
|
||||
|
||||
#endif // wxUSE_SOCKETS
|
||||
@@ -0,0 +1,223 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/sstream.cpp
|
||||
// Purpose: string-based streams implementation
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by: Ryan Norton (UTF8 UNICODE)
|
||||
// Created: 2004-09-19
|
||||
// Copyright: (c) 2004 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_STREAMS
|
||||
|
||||
#include "wx/sstream.h"
|
||||
|
||||
// ============================================================================
|
||||
// wxStringInputStream implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// construction/destruction
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// TODO: Do we want to include the null char in the stream? If so then
|
||||
// just add +1 to m_len in the ctor
|
||||
wxStringInputStream::wxStringInputStream(const wxString& s)
|
||||
#if wxUSE_UNICODE
|
||||
// FIXME-UTF8: use wxCharBufferWithLength if we have it
|
||||
: m_str(s), m_buf(s.utf8_str()), m_len(strlen(m_buf))
|
||||
#else
|
||||
: m_str(s), m_buf(s.mb_str()), m_len(s.length())
|
||||
#endif
|
||||
{
|
||||
#if wxUSE_UNICODE
|
||||
wxASSERT_MSG(m_buf.data() != NULL, wxT("Could not convert string to UTF8!"));
|
||||
#endif
|
||||
m_pos = 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// getlength
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxFileOffset wxStringInputStream::GetLength() const
|
||||
{
|
||||
return m_len;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// seek/tell
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxFileOffset wxStringInputStream::OnSysSeek(wxFileOffset ofs, wxSeekMode mode)
|
||||
{
|
||||
switch ( mode )
|
||||
{
|
||||
case wxFromStart:
|
||||
// nothing to do, ofs already ok
|
||||
break;
|
||||
|
||||
case wxFromEnd:
|
||||
ofs += m_len;
|
||||
break;
|
||||
|
||||
case wxFromCurrent:
|
||||
ofs += m_pos;
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( wxT("invalid seek mode") );
|
||||
return wxInvalidOffset;
|
||||
}
|
||||
|
||||
if ( ofs < 0 || ofs > static_cast<wxFileOffset>(m_len) )
|
||||
return wxInvalidOffset;
|
||||
|
||||
// FIXME: this can't be right
|
||||
m_pos = wx_truncate_cast(size_t, ofs);
|
||||
|
||||
return ofs;
|
||||
}
|
||||
|
||||
wxFileOffset wxStringInputStream::OnSysTell() const
|
||||
{
|
||||
return static_cast<wxFileOffset>(m_pos);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// actual IO
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
size_t wxStringInputStream::OnSysRead(void *buffer, size_t size)
|
||||
{
|
||||
const size_t sizeMax = m_len - m_pos;
|
||||
|
||||
if ( size >= sizeMax )
|
||||
{
|
||||
if ( sizeMax == 0 )
|
||||
{
|
||||
m_lasterror = wxSTREAM_EOF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = sizeMax;
|
||||
}
|
||||
|
||||
memcpy(buffer, m_buf.data() + m_pos, size);
|
||||
m_pos += size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// wxStringOutputStream implementation
|
||||
// ============================================================================
|
||||
|
||||
wxStringOutputStream::wxStringOutputStream(wxString *pString, wxMBConv& conv)
|
||||
: m_conv(conv)
|
||||
#if wxUSE_UNICODE
|
||||
, m_unconv(0)
|
||||
#endif // wxUSE_UNICODE
|
||||
{
|
||||
m_str = pString ? pString : &m_strInternal;
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
// We can avoid doing the conversion in the common case of using UTF-8
|
||||
// conversion in UTF-8 build, as it is exactly the same as the string
|
||||
// length anyhow in this case.
|
||||
#if wxUSE_UNICODE_UTF8
|
||||
if ( conv.IsUTF8() )
|
||||
m_pos = m_str->utf8_length();
|
||||
else
|
||||
#endif // wxUSE_UNICODE_UTF8
|
||||
m_pos = m_conv.FromWChar(NULL, 0, m_str->wc_str(), m_str->length());
|
||||
#else // !wxUSE_UNICODE
|
||||
m_pos = m_str->length();
|
||||
#endif // wxUSE_UNICODE/!wxUSE_UNICODE
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// seek/tell
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxFileOffset wxStringOutputStream::OnSysTell() const
|
||||
{
|
||||
return static_cast<wxFileOffset>(m_pos);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// actual IO
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
size_t wxStringOutputStream::OnSysWrite(const void *buffer, size_t size)
|
||||
{
|
||||
const char *p = static_cast<const char *>(buffer);
|
||||
|
||||
#if wxUSE_UNICODE
|
||||
// the part of the string we have here may be incomplete, i.e. it can stop
|
||||
// in the middle of an UTF-8 character and so converting it would fail; if
|
||||
// this is the case, accumulate the part which we failed to convert until
|
||||
// we get the rest (and also take into account the part which we might have
|
||||
// left unconverted before)
|
||||
const char *src;
|
||||
size_t srcLen;
|
||||
if ( m_unconv.GetDataLen() )
|
||||
{
|
||||
// append the new data to the data remaining since the last time
|
||||
m_unconv.AppendData(p, size);
|
||||
src = m_unconv;
|
||||
srcLen = m_unconv.GetDataLen();
|
||||
}
|
||||
else // no unconverted data left, avoid extra copy
|
||||
{
|
||||
src = p;
|
||||
srcLen = size;
|
||||
}
|
||||
|
||||
size_t wlen;
|
||||
wxWCharBuffer wbuf(m_conv.cMB2WC(src, srcLen, &wlen));
|
||||
if ( wbuf )
|
||||
{
|
||||
// conversion succeeded, clear the unconverted buffer
|
||||
m_unconv = wxMemoryBuffer(0);
|
||||
|
||||
m_str->append(wbuf, wlen);
|
||||
}
|
||||
else // conversion failed
|
||||
{
|
||||
// remember unconverted data if there had been none before (otherwise
|
||||
// we've already got it in the buffer)
|
||||
if ( src == p )
|
||||
m_unconv.AppendData(src, srcLen);
|
||||
|
||||
// pretend that we wrote the data anyhow, otherwise the caller would
|
||||
// believe there was an error and this might not be the case, but do
|
||||
// not update m_pos as m_str hasn't changed
|
||||
return size;
|
||||
}
|
||||
#else // !wxUSE_UNICODE
|
||||
// no recoding necessary
|
||||
m_str->append(p, size);
|
||||
#endif // wxUSE_UNICODE/!wxUSE_UNICODE
|
||||
|
||||
// update position
|
||||
m_pos += size;
|
||||
|
||||
// return number of bytes actually written
|
||||
return size;
|
||||
}
|
||||
|
||||
#endif // wxUSE_STREAMS
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/stdpbase.cpp
|
||||
// Purpose: wxStandardPathsBase methods common to all ports
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 2004-10-19
|
||||
// Copyright: (c) 2004 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/app.h"
|
||||
#endif //WX_PRECOMP
|
||||
#include "wx/apptrait.h"
|
||||
|
||||
#include "wx/filename.h"
|
||||
#include "wx/stdpaths.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// module globals
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Derive a class just to be able to create it: wxStandardPaths ctor is
|
||||
// protected to prevent its misuse, but it also means we can't create an object
|
||||
// of this class directly.
|
||||
class wxStandardPathsDefault : public wxStandardPaths
|
||||
{
|
||||
public:
|
||||
wxStandardPathsDefault() { }
|
||||
};
|
||||
|
||||
static wxStandardPathsDefault gs_stdPaths;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
/* static */
|
||||
wxStandardPaths& wxStandardPathsBase::Get()
|
||||
{
|
||||
wxAppTraits * const traits = wxApp::GetTraitsIfExists();
|
||||
wxCHECK_MSG( traits, gs_stdPaths, wxT("create wxApp before calling this") );
|
||||
|
||||
return traits->GetStandardPaths();
|
||||
}
|
||||
|
||||
wxString wxStandardPathsBase::GetExecutablePath() const
|
||||
{
|
||||
if ( !wxTheApp || !wxTheApp->argv )
|
||||
return wxEmptyString;
|
||||
|
||||
wxString argv0 = wxTheApp->argv[0];
|
||||
if (wxIsAbsolutePath(argv0))
|
||||
return argv0;
|
||||
|
||||
// Search PATH.environment variable...
|
||||
wxPathList pathlist;
|
||||
pathlist.AddEnvList(wxT("PATH"));
|
||||
wxString path = pathlist.FindAbsoluteValidPath(argv0);
|
||||
if ( path.empty() )
|
||||
return argv0; // better than nothing
|
||||
|
||||
wxFileName filename(path);
|
||||
filename.Normalize();
|
||||
return filename.GetFullPath();
|
||||
}
|
||||
|
||||
wxStandardPaths& wxAppTraitsBase::GetStandardPaths()
|
||||
{
|
||||
return gs_stdPaths;
|
||||
}
|
||||
|
||||
wxStandardPathsBase::wxStandardPathsBase()
|
||||
{
|
||||
// Set the default information that is used when
|
||||
// forming some paths (by AppendAppInfo).
|
||||
// Derived classes can call this in their constructors
|
||||
// to set the platform-specific settings
|
||||
UseAppInfo(AppInfo_AppName);
|
||||
|
||||
// Default for compatibility with the existing config files.
|
||||
SetFileLayout(FileLayout_Classic);
|
||||
}
|
||||
|
||||
wxStandardPathsBase::~wxStandardPathsBase()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
wxString wxStandardPathsBase::GetLocalDataDir() const
|
||||
{
|
||||
return GetDataDir();
|
||||
}
|
||||
|
||||
wxString wxStandardPathsBase::GetUserLocalDataDir() const
|
||||
{
|
||||
return GetUserDataDir();
|
||||
}
|
||||
|
||||
wxString wxStandardPathsBase::GetAppDocumentsDir() const
|
||||
{
|
||||
const wxString docsDir = GetDocumentsDir();
|
||||
wxString appDocsDir = AppendAppInfo(docsDir);
|
||||
|
||||
return wxDirExists(appDocsDir) ? appDocsDir : docsDir;
|
||||
}
|
||||
|
||||
// return the temporary directory for the current user
|
||||
wxString wxStandardPathsBase::GetTempDir() const
|
||||
{
|
||||
return wxFileName::GetTempDir();
|
||||
}
|
||||
|
||||
wxString wxStandardPathsBase::GetUserDir(Dir WXUNUSED(userDir)) const
|
||||
{
|
||||
return wxFileName::GetHomeDir();
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxString
|
||||
wxStandardPathsBase::AppendPathComponent(const wxString& dir,
|
||||
const wxString& component)
|
||||
{
|
||||
wxString subdir(dir);
|
||||
|
||||
// empty string indicates that an error has occurred, don't touch it then
|
||||
if ( !subdir.empty() )
|
||||
{
|
||||
if ( !component.empty() )
|
||||
{
|
||||
const wxChar ch = *(subdir.end() - 1);
|
||||
if ( !wxFileName::IsPathSeparator(ch) && ch != wxT('.') )
|
||||
subdir += wxFileName::GetPathSeparator();
|
||||
|
||||
subdir += component;
|
||||
}
|
||||
}
|
||||
|
||||
return subdir;
|
||||
}
|
||||
|
||||
|
||||
wxString wxStandardPathsBase::AppendAppInfo(const wxString& dir) const
|
||||
{
|
||||
wxString subdir(dir);
|
||||
|
||||
if ( UsesAppInfo(AppInfo_VendorName) )
|
||||
{
|
||||
subdir = AppendPathComponent(subdir, wxTheApp->GetVendorName());
|
||||
}
|
||||
|
||||
if ( UsesAppInfo(AppInfo_AppName) )
|
||||
{
|
||||
subdir = AppendPathComponent(subdir, wxTheApp->GetAppName());
|
||||
}
|
||||
|
||||
return subdir;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/stdstream.cpp
|
||||
// Purpose: Implementation of std::istream and std::ostream derived
|
||||
// wrappers for wxInputStream and wxOutputStream
|
||||
// Author: Jonathan Liu <net147@gmail.com>
|
||||
// Created: 2009-05-02
|
||||
// Copyright: (c) 2009 Jonathan Liu
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ==========================================================================
|
||||
// Declarations
|
||||
// ==========================================================================
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_STREAMS && wxUSE_STD_IOSTREAM
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#endif
|
||||
|
||||
#include "wx/stdstream.h"
|
||||
|
||||
#include <ios>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
|
||||
// ==========================================================================
|
||||
// Helpers
|
||||
// ==========================================================================
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool
|
||||
IosSeekDirToWxSeekMode(std::ios_base::seekdir way,
|
||||
wxSeekMode& seekMode)
|
||||
{
|
||||
switch ( way )
|
||||
{
|
||||
case std::ios_base::beg:
|
||||
seekMode = wxFromStart;
|
||||
break;
|
||||
case std::ios_base::cur:
|
||||
seekMode = wxFromCurrent;
|
||||
break;
|
||||
case std::ios_base::end:
|
||||
seekMode = wxFromEnd;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ==========================================================================
|
||||
// wxStdInputStreamBuffer
|
||||
// ==========================================================================
|
||||
|
||||
wxStdInputStreamBuffer::wxStdInputStreamBuffer(wxInputStream& stream) :
|
||||
m_stream(stream), m_lastChar(EOF)
|
||||
{
|
||||
}
|
||||
|
||||
std::streambuf *
|
||||
wxStdInputStreamBuffer::setbuf(char *WXUNUSED(s),
|
||||
std::streamsize WXUNUSED(n))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::streampos
|
||||
wxStdInputStreamBuffer::seekoff(std::streamoff off,
|
||||
std::ios_base::seekdir way,
|
||||
std::ios_base::openmode which)
|
||||
{
|
||||
wxSeekMode seekMode;
|
||||
|
||||
if ( !IosSeekDirToWxSeekMode(way, seekMode) )
|
||||
return -1;
|
||||
if ( !(which & std::ios_base::in) )
|
||||
return -1;
|
||||
|
||||
off_t newPos = m_stream.SeekI((off_t) off, seekMode);
|
||||
|
||||
if ( newPos != wxInvalidOffset )
|
||||
return (std::streampos) newPos;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::streampos
|
||||
wxStdInputStreamBuffer::seekpos(std::streampos sp,
|
||||
std::ios_base::openmode which)
|
||||
{
|
||||
if ( !(which & std::ios_base::in) )
|
||||
return -1;
|
||||
|
||||
off_t newPos = m_stream.SeekI((off_t) sp);
|
||||
|
||||
if ( newPos != wxInvalidOffset )
|
||||
return (std::streampos) newPos;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::streamsize
|
||||
wxStdInputStreamBuffer::showmanyc()
|
||||
{
|
||||
if ( m_stream.CanRead() && (off_t) m_stream.GetSize() > m_stream.TellI() )
|
||||
return m_stream.GetSize() - m_stream.TellI();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::streamsize
|
||||
wxStdInputStreamBuffer::xsgetn(char *s, std::streamsize n)
|
||||
{
|
||||
m_stream.Read((void *) s, (size_t) n);
|
||||
|
||||
std::streamsize read = m_stream.LastRead();
|
||||
|
||||
if ( read > 0 )
|
||||
m_lastChar = (unsigned char) s[read - 1];
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
int
|
||||
wxStdInputStreamBuffer::underflow()
|
||||
{
|
||||
int ch = m_stream.GetC();
|
||||
|
||||
if ( m_stream.LastRead() == 1 )
|
||||
{
|
||||
m_stream.Ungetch((char) ch);
|
||||
return ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
wxStdInputStreamBuffer::uflow()
|
||||
{
|
||||
int ch = m_stream.GetC();
|
||||
|
||||
if ( m_stream.LastRead() == 1 )
|
||||
{
|
||||
m_lastChar = ch;
|
||||
return ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
wxStdInputStreamBuffer::pbackfail(int c)
|
||||
{
|
||||
if ( c == EOF )
|
||||
{
|
||||
if ( m_lastChar == EOF )
|
||||
return EOF;
|
||||
|
||||
c = m_lastChar;
|
||||
m_lastChar = EOF;
|
||||
}
|
||||
|
||||
return m_stream.Ungetch((char) c) ? c : EOF;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// wxStdOutputStreamBuffer
|
||||
// ==========================================================================
|
||||
|
||||
wxStdOutputStreamBuffer::wxStdOutputStreamBuffer(wxOutputStream& stream) :
|
||||
m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
std::streambuf *
|
||||
wxStdOutputStreamBuffer::setbuf(char *WXUNUSED(s),
|
||||
std::streamsize WXUNUSED(n))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::streampos
|
||||
wxStdOutputStreamBuffer::seekoff(std::streamoff off,
|
||||
std::ios_base::seekdir way,
|
||||
std::ios_base::openmode which)
|
||||
{
|
||||
wxSeekMode seekMode;
|
||||
|
||||
if ( !IosSeekDirToWxSeekMode(way, seekMode) )
|
||||
return -1;
|
||||
if ( !(which & std::ios_base::out) )
|
||||
return -1;
|
||||
|
||||
off_t newPos = m_stream.SeekO((off_t) off, seekMode);
|
||||
|
||||
if ( newPos != wxInvalidOffset )
|
||||
return (std::streampos) newPos;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::streampos
|
||||
wxStdOutputStreamBuffer::seekpos(std::streampos sp,
|
||||
std::ios_base::openmode which)
|
||||
{
|
||||
if ( !(which & std::ios_base::out) )
|
||||
return -1;
|
||||
|
||||
off_t newPos = m_stream.SeekO((off_t) sp);
|
||||
|
||||
if ( newPos != wxInvalidOffset )
|
||||
return (std::streampos) newPos;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::streamsize
|
||||
wxStdOutputStreamBuffer::xsputn(const char *s,
|
||||
std::streamsize n)
|
||||
{
|
||||
m_stream.Write((const void *) s, (size_t) n);
|
||||
return (std::streamsize) m_stream.LastWrite();
|
||||
}
|
||||
|
||||
int
|
||||
wxStdOutputStreamBuffer::overflow(int c)
|
||||
{
|
||||
m_stream.PutC(c);
|
||||
return m_stream.IsOk() ? c : EOF;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// wxStdInputStream and wxStdOutputStream
|
||||
// ==========================================================================
|
||||
|
||||
wxStdInputStream::wxStdInputStream(wxInputStream& stream) :
|
||||
std::istream(NULL), m_streamBuffer(stream)
|
||||
{
|
||||
std::ios::init(&m_streamBuffer);
|
||||
}
|
||||
|
||||
wxStdOutputStream::wxStdOutputStream(wxOutputStream& stream) :
|
||||
std::ostream(NULL), m_streamBuffer(stream)
|
||||
{
|
||||
std::ios::init(&m_streamBuffer);
|
||||
}
|
||||
|
||||
#endif // wxUSE_STREAMS && wxUSE_STD_IOSTREAM
|
||||
@@ -0,0 +1,176 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/stopwatch.cpp
|
||||
// Purpose: wxStopWatch and other non-GUI stuff from wx/timer.h
|
||||
// Author:
|
||||
// Original version by Julian Smart
|
||||
// Vadim Zeitlin got rid of all ifdefs (11.12.99)
|
||||
// Sylvain Bougnoux added wxStopWatch class
|
||||
// Guillermo Rodriguez <guille@iies.es> rewrote from scratch (Dic/99)
|
||||
// Modified by:
|
||||
// Created: 20.06.2003 (extracted from common/timercmn.cpp)
|
||||
// Copyright: (c) 1998-2003 wxWidgets Team
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/stopwatch.h"
|
||||
|
||||
#if wxUSE_STOPWATCH
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#ifdef __WINDOWS__
|
||||
#include "wx/msw/wrapwin.h"
|
||||
#endif
|
||||
#include "wx/log.h"
|
||||
#include "wx/thread.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxStopWatch
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
struct PerfCounter
|
||||
{
|
||||
PerfCounter()
|
||||
{
|
||||
init = false;
|
||||
}
|
||||
|
||||
wxCRIT_SECT_DECLARE_MEMBER(cs);
|
||||
LARGE_INTEGER freq;
|
||||
bool init;
|
||||
};
|
||||
|
||||
// Return the global perf counter state.
|
||||
//
|
||||
// This is wrapped in a function to avoid initialization order problems,
|
||||
// otherwise simply creating a global wxStopWatch variable could crash because
|
||||
// it would be using a (possibly) still uninitialized critical section.
|
||||
PerfCounter& GetPerfCounterState()
|
||||
{
|
||||
static PerfCounter s_perfCounter;
|
||||
|
||||
return s_perfCounter;
|
||||
}
|
||||
|
||||
#endif // __WINDOWS__
|
||||
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int MICROSECONDS_PER_SECOND = 1000*1000;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void wxStopWatch::DoStart()
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
PerfCounter& perfCounter = GetPerfCounterState();
|
||||
if ( !perfCounter.init )
|
||||
{
|
||||
wxCRIT_SECT_LOCKER(lock, perfCounter.cs);
|
||||
::QueryPerformanceFrequency(&perfCounter.freq);
|
||||
|
||||
perfCounter.init = true;
|
||||
}
|
||||
#endif // __WINDOWS__
|
||||
|
||||
m_t0 = GetCurrentClockValue();
|
||||
}
|
||||
|
||||
wxLongLong wxStopWatch::GetClockFreq() const
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
// Under MSW we use the high resolution performance counter timer which has
|
||||
// its own frequency (usually related to the CPU clock speed).
|
||||
return GetPerfCounterState().freq.QuadPart;
|
||||
#elif defined(HAVE_GETTIMEOFDAY)
|
||||
// With gettimeofday() we can have nominally microsecond precision and
|
||||
// while this is not the case in practice, it's still better than
|
||||
// millisecond.
|
||||
return MICROSECONDS_PER_SECOND;
|
||||
#else // !HAVE_GETTIMEOFDAY
|
||||
// Currently milliseconds are used everywhere else.
|
||||
return MILLISECONDS_PER_SECOND;
|
||||
#endif // __WINDOWS__/HAVE_GETTIMEOFDAY/else
|
||||
}
|
||||
|
||||
void wxStopWatch::Start(long t0)
|
||||
{
|
||||
// Calling Start() makes the stop watch run however many times it was
|
||||
// paused before.
|
||||
m_pauseCount = 0;
|
||||
|
||||
DoStart();
|
||||
|
||||
m_t0 -= (wxLongLong(t0)*GetClockFreq())/MILLISECONDS_PER_SECOND;
|
||||
}
|
||||
|
||||
wxLongLong wxStopWatch::GetCurrentClockValue() const
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
LARGE_INTEGER counter;
|
||||
::QueryPerformanceCounter(&counter);
|
||||
return counter.QuadPart;
|
||||
#elif defined(HAVE_GETTIMEOFDAY)
|
||||
return wxGetUTCTimeUSec();
|
||||
#else // !HAVE_GETTIMEOFDAY
|
||||
return wxGetUTCTimeMillis();
|
||||
#endif // __WINDOWS__/HAVE_GETTIMEOFDAY/else
|
||||
}
|
||||
|
||||
wxLongLong wxStopWatch::TimeInMicro() const
|
||||
{
|
||||
const wxLongLong elapsed(m_pauseCount ? m_elapsedBeforePause
|
||||
: GetCurrentClockValue() - m_t0);
|
||||
|
||||
return (elapsed*MICROSECONDS_PER_SECOND)/GetClockFreq();
|
||||
}
|
||||
|
||||
#endif // wxUSE_STOPWATCH
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// old timer functions superceded by wxStopWatch
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_LONGLONG
|
||||
|
||||
static wxLongLong wxStartTime = 0l;
|
||||
|
||||
// starts the global timer
|
||||
void wxStartTimer()
|
||||
{
|
||||
wxStartTime = wxGetUTCTimeMillis();
|
||||
}
|
||||
|
||||
// Returns elapsed time in milliseconds
|
||||
long wxGetElapsedTime(bool resetTimer)
|
||||
{
|
||||
wxLongLong oldTime = wxStartTime;
|
||||
wxLongLong newTime = wxGetUTCTimeMillis();
|
||||
|
||||
if ( resetTimer )
|
||||
wxStartTime = newTime;
|
||||
|
||||
return (newTime - oldTime).GetLo();
|
||||
}
|
||||
|
||||
#endif // wxUSE_LONGLONG
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,791 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/stringimpl.cpp
|
||||
// Purpose: wxString class
|
||||
// Author: Vadim Zeitlin, Ryan Norton
|
||||
// Modified by:
|
||||
// Created: 29/01/98
|
||||
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
|
||||
// (c) 2004 Ryan Norton <wxprojects@comcast.net>
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* About ref counting:
|
||||
* 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
|
||||
* 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one
|
||||
* 3) Unlock() decrements nRefs and frees memory if it goes to 0
|
||||
*/
|
||||
|
||||
// ===========================================================================
|
||||
// headers, declarations, constants
|
||||
// ===========================================================================
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/stringimpl.h"
|
||||
#include "wx/wxcrt.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// static class variables definition
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#if !wxUSE_STL_BASED_WXSTRING
|
||||
//According to STL _must_ be a -1 size_t
|
||||
const size_t wxStringImpl::npos = (size_t) -1;
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// static data
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_STL_BASED_WXSTRING
|
||||
|
||||
// FIXME-UTF8: get rid of this, have only one wxEmptyString
|
||||
#if wxUSE_UNICODE_UTF8
|
||||
const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyStringImpl = "";
|
||||
#endif
|
||||
const wxChar WXDLLIMPEXP_BASE *wxEmptyString = wxT("");
|
||||
|
||||
#else
|
||||
|
||||
// allocating extra space for each string consumes more memory but speeds up
|
||||
// the concatenation operations (nLen is the current string's length)
|
||||
// NB: EXTRA_ALLOC must be >= 0!
|
||||
#define EXTRA_ALLOC (19 - nLen % 16)
|
||||
|
||||
// string handling functions used by wxString:
|
||||
#if wxUSE_UNICODE_UTF8
|
||||
#define wxStringMemcpy memcpy
|
||||
#define wxStringMemcmp memcmp
|
||||
#define wxStringMemchr memchr
|
||||
#else
|
||||
#define wxStringMemcpy wxTmemcpy
|
||||
#define wxStringMemcmp wxTmemcmp
|
||||
#define wxStringMemchr wxTmemchr
|
||||
#endif
|
||||
|
||||
// for an empty string, GetStringData() will return this address: this
|
||||
// structure has the same layout as wxStringData and it's data() method will
|
||||
// return the empty string (dummy pointer)
|
||||
static const struct
|
||||
{
|
||||
wxStringData data;
|
||||
wxStringCharType dummy;
|
||||
} g_strEmpty = { {-1, 0, 0}, wxT('\0') };
|
||||
|
||||
// empty C style string: points to 'string data' byte of g_strEmpty
|
||||
#if wxUSE_UNICODE_UTF8
|
||||
// FIXME-UTF8: get rid of this, have only one wxEmptyString
|
||||
const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyStringImpl = &g_strEmpty.dummy;
|
||||
const wxChar WXDLLIMPEXP_BASE *wxEmptyString = wxT("");
|
||||
#else
|
||||
const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if !wxUSE_STL_BASED_WXSTRING
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// private classes
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// this small class is used to gather statistics for performance tuning
|
||||
|
||||
// uncomment this to enable gathering of some statistics about wxString
|
||||
// efficiency
|
||||
//#define WXSTRING_STATISTICS
|
||||
|
||||
#ifdef WXSTRING_STATISTICS
|
||||
class Averager
|
||||
{
|
||||
public:
|
||||
Averager(const wxStringCharType *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
|
||||
~Averager()
|
||||
{
|
||||
wxPrintf("wxString %s: total = %lu, average = %f\n",
|
||||
m_sz, m_nTotal, ((float)m_nTotal)/m_nCount);
|
||||
}
|
||||
|
||||
void Add(size_t n) { m_nTotal += n; m_nCount++; }
|
||||
|
||||
private:
|
||||
unsigned long m_nCount, m_nTotal;
|
||||
const wxStringCharType *m_sz;
|
||||
} g_averageLength("allocation size"),
|
||||
g_averageSummandLength("summand length"),
|
||||
g_averageConcatHit("hit probability in concat"),
|
||||
g_averageInitialLength("initial string length");
|
||||
|
||||
#define STATISTICS_ADD(av, val) g_average##av.Add(val)
|
||||
#else
|
||||
#define STATISTICS_ADD(av, val)
|
||||
#endif // WXSTRING_STATISTICS
|
||||
|
||||
// ===========================================================================
|
||||
// wxStringData class deallocation
|
||||
// ===========================================================================
|
||||
|
||||
#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL)
|
||||
# pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!")
|
||||
void wxStringData::Free()
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ===========================================================================
|
||||
// wxStringImpl
|
||||
// ===========================================================================
|
||||
|
||||
// takes nLength elements of psz starting at nPos
|
||||
void wxStringImpl::InitWith(const wxStringCharType *psz,
|
||||
size_t nPos, size_t nLength)
|
||||
{
|
||||
Init();
|
||||
|
||||
// if the length is not given, assume the string to be NUL terminated
|
||||
if ( nLength == npos ) {
|
||||
wxASSERT_MSG( nPos <= wxStrlen(psz), wxT("index out of bounds") );
|
||||
|
||||
nLength = wxStrlen(psz + nPos);
|
||||
}
|
||||
|
||||
STATISTICS_ADD(InitialLength, nLength);
|
||||
|
||||
if ( nLength > 0 ) {
|
||||
// trailing '\0' is written in AllocBuffer()
|
||||
if ( !AllocBuffer(nLength) ) {
|
||||
wxFAIL_MSG( wxT("out of memory in wxStringImpl::InitWith") );
|
||||
return;
|
||||
}
|
||||
wxStringMemcpy(m_pchData, psz + nPos, nLength);
|
||||
}
|
||||
}
|
||||
|
||||
wxStringImpl::wxStringImpl(const_iterator first, const_iterator last)
|
||||
{
|
||||
if ( last >= first )
|
||||
{
|
||||
InitWith(first.GetPtr(), 0, last - first);
|
||||
}
|
||||
else
|
||||
{
|
||||
wxFAIL_MSG( wxT("first must be before last") );
|
||||
Init();
|
||||
}
|
||||
}
|
||||
|
||||
wxStringImpl::wxStringImpl(size_type n, wxStringCharType ch)
|
||||
{
|
||||
Init();
|
||||
append(n, ch);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// memory allocation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// allocates memory needed to store a C string of length nLen
|
||||
bool wxStringImpl::AllocBuffer(size_t nLen)
|
||||
{
|
||||
// allocating 0 sized buffer doesn't make sense, all empty strings should
|
||||
// reuse g_strEmpty
|
||||
wxASSERT( nLen > 0 );
|
||||
|
||||
// make sure that we don't overflow
|
||||
wxCHECK( nLen < (INT_MAX / sizeof(wxStringCharType)) -
|
||||
(sizeof(wxStringData) + EXTRA_ALLOC + 1), false );
|
||||
|
||||
STATISTICS_ADD(Length, nLen);
|
||||
|
||||
// allocate memory:
|
||||
// 1) one extra character for '\0' termination
|
||||
// 2) sizeof(wxStringData) for housekeeping info
|
||||
wxStringData* pData = (wxStringData*)
|
||||
malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxStringCharType));
|
||||
|
||||
if ( pData == NULL ) {
|
||||
// allocation failures are handled by the caller
|
||||
return false;
|
||||
}
|
||||
|
||||
pData->nRefs = 1;
|
||||
pData->nDataLength = nLen;
|
||||
pData->nAllocLength = nLen + EXTRA_ALLOC;
|
||||
m_pchData = pData->data(); // data starts after wxStringData
|
||||
m_pchData[nLen] = wxT('\0');
|
||||
return true;
|
||||
}
|
||||
|
||||
// must be called before changing this string
|
||||
bool wxStringImpl::CopyBeforeWrite()
|
||||
{
|
||||
wxStringData* pData = GetStringData();
|
||||
|
||||
if ( pData->IsShared() ) {
|
||||
pData->Unlock(); // memory not freed because shared
|
||||
size_t nLen = pData->nDataLength;
|
||||
if ( !AllocBuffer(nLen) ) {
|
||||
// allocation failures are handled by the caller
|
||||
return false;
|
||||
}
|
||||
wxStringMemcpy(m_pchData, pData->data(), nLen);
|
||||
}
|
||||
|
||||
wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// must be called before replacing contents of this string
|
||||
bool wxStringImpl::AllocBeforeWrite(size_t nLen)
|
||||
{
|
||||
wxASSERT( nLen != 0 ); // doesn't make any sense
|
||||
|
||||
// must not share string and must have enough space
|
||||
wxStringData* pData = GetStringData();
|
||||
if ( pData->IsShared() || pData->IsEmpty() ) {
|
||||
// can't work with old buffer, get new one
|
||||
pData->Unlock();
|
||||
if ( !AllocBuffer(nLen) ) {
|
||||
// allocation failures are handled by the caller
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( nLen > pData->nAllocLength ) {
|
||||
// realloc the buffer instead of calling malloc() again, this is more
|
||||
// efficient
|
||||
STATISTICS_ADD(Length, nLen);
|
||||
|
||||
nLen += EXTRA_ALLOC;
|
||||
|
||||
pData = (wxStringData*)
|
||||
realloc(pData,
|
||||
sizeof(wxStringData) + (nLen + 1)*sizeof(wxStringCharType));
|
||||
|
||||
if ( pData == NULL ) {
|
||||
// allocation failures are handled by the caller
|
||||
// keep previous data since reallocation failed
|
||||
return false;
|
||||
}
|
||||
|
||||
pData->nAllocLength = nLen;
|
||||
m_pchData = pData->data();
|
||||
}
|
||||
}
|
||||
|
||||
wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
|
||||
|
||||
// it doesn't really matter what the string length is as it's going to be
|
||||
// overwritten later but, for extra safety, set it to 0 for now as we may
|
||||
// have some junk in m_pchData
|
||||
GetStringData()->nDataLength = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
wxStringImpl& wxStringImpl::append(size_t n, wxStringCharType ch)
|
||||
{
|
||||
size_type len = length();
|
||||
|
||||
if ( !Alloc(len + n) || !CopyBeforeWrite() ) {
|
||||
wxFAIL_MSG( wxT("out of memory in wxStringImpl::append") );
|
||||
return *this;
|
||||
}
|
||||
GetStringData()->nDataLength = len + n;
|
||||
m_pchData[len + n] = '\0';
|
||||
for ( size_t i = 0; i < n; ++i )
|
||||
m_pchData[len + i] = ch;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void wxStringImpl::resize(size_t nSize, wxStringCharType ch)
|
||||
{
|
||||
size_t len = length();
|
||||
|
||||
if ( nSize < len )
|
||||
{
|
||||
erase(begin() + nSize, end());
|
||||
}
|
||||
else if ( nSize > len )
|
||||
{
|
||||
append(nSize - len, ch);
|
||||
}
|
||||
//else: we have exactly the specified length, nothing to do
|
||||
}
|
||||
|
||||
// allocate enough memory for nLen characters
|
||||
bool wxStringImpl::Alloc(size_t nLen)
|
||||
{
|
||||
wxStringData *pData = GetStringData();
|
||||
if ( pData->nAllocLength <= nLen ) {
|
||||
if ( pData->IsEmpty() ) {
|
||||
STATISTICS_ADD(Length, nLen);
|
||||
|
||||
nLen += EXTRA_ALLOC;
|
||||
|
||||
pData = (wxStringData *)
|
||||
malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxStringCharType));
|
||||
|
||||
if ( pData == NULL ) {
|
||||
// allocation failure handled by caller
|
||||
return false;
|
||||
}
|
||||
|
||||
pData->nRefs = 1;
|
||||
pData->nDataLength = 0;
|
||||
pData->nAllocLength = nLen;
|
||||
m_pchData = pData->data(); // data starts after wxStringData
|
||||
m_pchData[0u] = wxT('\0');
|
||||
}
|
||||
else if ( pData->IsShared() ) {
|
||||
pData->Unlock(); // memory not freed because shared
|
||||
size_t nOldLen = pData->nDataLength;
|
||||
if ( !AllocBuffer(nLen) ) {
|
||||
// allocation failure handled by caller
|
||||
return false;
|
||||
}
|
||||
// +1 to copy the terminator, too
|
||||
memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxStringCharType));
|
||||
GetStringData()->nDataLength = nOldLen;
|
||||
}
|
||||
else {
|
||||
nLen += EXTRA_ALLOC;
|
||||
|
||||
pData = (wxStringData *)
|
||||
realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxStringCharType));
|
||||
|
||||
if ( pData == NULL ) {
|
||||
// allocation failure handled by caller
|
||||
// keep previous data since reallocation failed
|
||||
return false;
|
||||
}
|
||||
|
||||
// it's not important if the pointer changed or not (the check for this
|
||||
// is not faster than assigning to m_pchData in all cases)
|
||||
pData->nAllocLength = nLen;
|
||||
m_pchData = pData->data();
|
||||
}
|
||||
}
|
||||
//else: we've already got enough
|
||||
return true;
|
||||
}
|
||||
|
||||
wxStringImpl::iterator wxStringImpl::begin()
|
||||
{
|
||||
if ( !empty() )
|
||||
CopyBeforeWrite();
|
||||
return m_pchData;
|
||||
}
|
||||
|
||||
wxStringImpl::iterator wxStringImpl::end()
|
||||
{
|
||||
if ( !empty() )
|
||||
CopyBeforeWrite();
|
||||
return m_pchData + length();
|
||||
}
|
||||
|
||||
wxStringImpl::iterator wxStringImpl::erase(iterator it)
|
||||
{
|
||||
size_type idx = it - begin();
|
||||
erase(idx, 1);
|
||||
return begin() + idx;
|
||||
}
|
||||
|
||||
wxStringImpl& wxStringImpl::erase(size_t nStart, size_t nLen)
|
||||
{
|
||||
wxASSERT(nStart <= length());
|
||||
size_t strLen = length() - nStart;
|
||||
// delete nLen or up to the end of the string characters
|
||||
nLen = strLen < nLen ? strLen : nLen;
|
||||
wxStringImpl strTmp(c_str(), nStart);
|
||||
strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen);
|
||||
|
||||
swap(strTmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxStringImpl& wxStringImpl::insert(size_t nPos,
|
||||
const wxStringCharType *sz, size_t n)
|
||||
{
|
||||
wxASSERT( nPos <= length() );
|
||||
|
||||
if ( n == npos ) n = wxStrlen(sz);
|
||||
if ( n == 0 ) return *this;
|
||||
|
||||
if ( !Alloc(length() + n) || !CopyBeforeWrite() ) {
|
||||
wxFAIL_MSG( wxT("out of memory in wxStringImpl::insert") );
|
||||
return *this;
|
||||
}
|
||||
|
||||
memmove(m_pchData + nPos + n, m_pchData + nPos,
|
||||
(length() - nPos) * sizeof(wxStringCharType));
|
||||
memcpy(m_pchData + nPos, sz, n * sizeof(wxStringCharType));
|
||||
GetStringData()->nDataLength = length() + n;
|
||||
m_pchData[length()] = '\0';
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void wxStringImpl::swap(wxStringImpl& str)
|
||||
{
|
||||
wxStringCharType* tmp = str.m_pchData;
|
||||
str.m_pchData = m_pchData;
|
||||
m_pchData = tmp;
|
||||
}
|
||||
|
||||
size_t wxStringImpl::find(const wxStringImpl& str, size_t nStart) const
|
||||
{
|
||||
// deal with the special case of empty string first
|
||||
const size_t nLen = length();
|
||||
const size_t nLenOther = str.length();
|
||||
|
||||
if ( !nLenOther )
|
||||
{
|
||||
// empty string is a substring of anything
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( !nLen )
|
||||
{
|
||||
// the other string is non empty so can't be our substring
|
||||
return npos;
|
||||
}
|
||||
|
||||
wxASSERT( str.GetStringData()->IsValid() );
|
||||
wxASSERT( nStart <= nLen );
|
||||
|
||||
const wxStringCharType * const other = str.c_str();
|
||||
|
||||
// anchor
|
||||
const wxStringCharType* p =
|
||||
(const wxStringCharType*)wxStringMemchr(c_str() + nStart,
|
||||
*other,
|
||||
nLen - nStart);
|
||||
|
||||
if ( !p )
|
||||
return npos;
|
||||
|
||||
while ( p - c_str() + nLenOther <= nLen &&
|
||||
wxStringMemcmp(p, other, nLenOther) )
|
||||
{
|
||||
p++;
|
||||
|
||||
// anchor again
|
||||
p = (const wxStringCharType*)
|
||||
wxStringMemchr(p, *other, nLen - (p - c_str()));
|
||||
|
||||
if ( !p )
|
||||
return npos;
|
||||
}
|
||||
|
||||
return p - c_str() + nLenOther <= nLen ? p - c_str() : npos;
|
||||
}
|
||||
|
||||
size_t wxStringImpl::find(const wxStringCharType* sz,
|
||||
size_t nStart, size_t n) const
|
||||
{
|
||||
return find(wxStringImpl(sz, n), nStart);
|
||||
}
|
||||
|
||||
size_t wxStringImpl::find(wxStringCharType ch, size_t nStart) const
|
||||
{
|
||||
wxASSERT( nStart <= length() );
|
||||
|
||||
const wxStringCharType *p = (const wxStringCharType*)
|
||||
wxStringMemchr(c_str() + nStart, ch, length() - nStart);
|
||||
|
||||
return p == NULL ? npos : p - c_str();
|
||||
}
|
||||
|
||||
size_t wxStringImpl::rfind(const wxStringImpl& str, size_t nStart) const
|
||||
{
|
||||
wxASSERT( str.GetStringData()->IsValid() );
|
||||
wxASSERT( nStart == npos || nStart <= length() );
|
||||
|
||||
if ( length() >= str.length() )
|
||||
{
|
||||
// avoids a corner case later
|
||||
if ( empty() && str.empty() )
|
||||
return 0;
|
||||
|
||||
// "top" is the point where search starts from
|
||||
size_t top = length() - str.length();
|
||||
|
||||
if ( nStart == npos )
|
||||
nStart = length() - 1;
|
||||
if ( nStart < top )
|
||||
top = nStart;
|
||||
|
||||
const wxStringCharType *cursor = c_str() + top;
|
||||
do
|
||||
{
|
||||
if ( wxStringMemcmp(cursor, str.c_str(), str.length()) == 0 )
|
||||
{
|
||||
return cursor - c_str();
|
||||
}
|
||||
} while ( cursor-- > c_str() );
|
||||
}
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t wxStringImpl::rfind(const wxStringCharType* sz,
|
||||
size_t nStart, size_t n) const
|
||||
{
|
||||
return rfind(wxStringImpl(sz, n), nStart);
|
||||
}
|
||||
|
||||
size_t wxStringImpl::rfind(wxStringCharType ch, size_t nStart) const
|
||||
{
|
||||
if ( nStart == npos )
|
||||
{
|
||||
nStart = length();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxASSERT( nStart <= length() );
|
||||
}
|
||||
|
||||
const wxStringCharType *actual;
|
||||
for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 );
|
||||
actual > c_str(); --actual )
|
||||
{
|
||||
if ( *(actual - 1) == ch )
|
||||
return (actual - 1) - c_str();
|
||||
}
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen,
|
||||
const wxStringCharType *sz, size_t nCount)
|
||||
{
|
||||
// check and adjust parameters
|
||||
const size_t lenOld = length();
|
||||
|
||||
wxASSERT_MSG( nStart <= lenOld,
|
||||
wxT("index out of bounds in wxStringImpl::replace") );
|
||||
size_t nEnd = nStart + nLen;
|
||||
if ( nLen > lenOld - nStart )
|
||||
{
|
||||
// nLen may be out of range, as it can be npos, just clump it down
|
||||
nLen = lenOld - nStart;
|
||||
nEnd = lenOld;
|
||||
}
|
||||
|
||||
if ( nCount == npos )
|
||||
nCount = wxStrlen(sz);
|
||||
|
||||
// build the new string from 3 pieces: part of this string before nStart,
|
||||
// the new substring and the part of this string after nStart+nLen
|
||||
wxStringImpl tmp;
|
||||
const size_t lenNew = lenOld + nCount - nLen;
|
||||
if ( lenNew )
|
||||
{
|
||||
tmp.AllocBuffer(lenOld + nCount - nLen);
|
||||
|
||||
wxStringCharType *dst = tmp.m_pchData;
|
||||
memcpy(dst, m_pchData, nStart*sizeof(wxStringCharType));
|
||||
dst += nStart;
|
||||
|
||||
memcpy(dst, sz, nCount*sizeof(wxStringCharType));
|
||||
dst += nCount;
|
||||
|
||||
memcpy(dst, m_pchData + nEnd, (lenOld - nEnd)*sizeof(wxStringCharType));
|
||||
}
|
||||
|
||||
// and replace this string contents with the new one
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxStringImpl wxStringImpl::substr(size_t nStart, size_t nLen) const
|
||||
{
|
||||
if ( nLen == npos )
|
||||
nLen = length() - nStart;
|
||||
return wxStringImpl(*this, nStart, nLen);
|
||||
}
|
||||
|
||||
// assigns one string to another
|
||||
wxStringImpl& wxStringImpl::operator=(const wxStringImpl& stringSrc)
|
||||
{
|
||||
wxASSERT( stringSrc.GetStringData()->IsValid() );
|
||||
|
||||
// don't copy string over itself
|
||||
if ( m_pchData != stringSrc.m_pchData ) {
|
||||
if ( stringSrc.GetStringData()->IsEmpty() ) {
|
||||
Reinit();
|
||||
}
|
||||
else {
|
||||
// adjust references
|
||||
GetStringData()->Unlock();
|
||||
m_pchData = stringSrc.m_pchData;
|
||||
GetStringData()->Lock();
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// assigns a single character
|
||||
wxStringImpl& wxStringImpl::operator=(wxStringCharType ch)
|
||||
{
|
||||
wxStringCharType c(ch);
|
||||
if ( !AssignCopy(1, &c) ) {
|
||||
wxFAIL_MSG( wxT("out of memory in wxStringImpl::operator=(wxStringCharType)") );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// assigns C string
|
||||
wxStringImpl& wxStringImpl::operator=(const wxStringCharType *psz)
|
||||
{
|
||||
if ( !AssignCopy(wxStrlen(psz), psz) ) {
|
||||
wxFAIL_MSG( wxT("out of memory in wxStringImpl::operator=(const wxStringCharType *)") );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// helper function: does real copy
|
||||
bool wxStringImpl::AssignCopy(size_t nSrcLen,
|
||||
const wxStringCharType *pszSrcData)
|
||||
{
|
||||
if ( nSrcLen == 0 ) {
|
||||
Reinit();
|
||||
}
|
||||
else {
|
||||
if ( !AllocBeforeWrite(nSrcLen) ) {
|
||||
// allocation failure handled by caller
|
||||
return false;
|
||||
}
|
||||
|
||||
// use memmove() and not memcpy() here as we might be copying from our own
|
||||
// buffer in case of assignment such as "s = s.c_str()" (see #11294)
|
||||
memmove(m_pchData, pszSrcData, nSrcLen*sizeof(wxStringCharType));
|
||||
|
||||
GetStringData()->nDataLength = nSrcLen;
|
||||
m_pchData[nSrcLen] = wxT('\0');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// string concatenation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// add something to this string
|
||||
bool wxStringImpl::ConcatSelf(size_t nSrcLen,
|
||||
const wxStringCharType *pszSrcData,
|
||||
size_t nMaxLen)
|
||||
{
|
||||
STATISTICS_ADD(SummandLength, nSrcLen);
|
||||
|
||||
nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
|
||||
|
||||
// concatenating an empty string is a NOP
|
||||
if ( nSrcLen > 0 ) {
|
||||
wxStringData *pData = GetStringData();
|
||||
size_t nLen = pData->nDataLength;
|
||||
|
||||
// take special care when appending part of this string to itself: the code
|
||||
// below reallocates our buffer and this invalidates pszSrcData pointer so
|
||||
// we have to copy it in another temporary string in this case (but avoid
|
||||
// doing this unnecessarily)
|
||||
if ( pszSrcData >= m_pchData && pszSrcData < m_pchData + nLen )
|
||||
{
|
||||
wxStringImpl tmp(pszSrcData, nSrcLen);
|
||||
return ConcatSelf(nSrcLen, tmp.m_pchData, nSrcLen);
|
||||
}
|
||||
|
||||
size_t nNewLen = nLen + nSrcLen;
|
||||
|
||||
// alloc new buffer if current is too small
|
||||
if ( pData->IsShared() ) {
|
||||
STATISTICS_ADD(ConcatHit, 0);
|
||||
|
||||
// we have to allocate another buffer
|
||||
wxStringData* pOldData = GetStringData();
|
||||
if ( !AllocBuffer(nNewLen) ) {
|
||||
// allocation failure handled by caller
|
||||
return false;
|
||||
}
|
||||
memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxStringCharType));
|
||||
pOldData->Unlock();
|
||||
}
|
||||
else if ( nNewLen > pData->nAllocLength ) {
|
||||
STATISTICS_ADD(ConcatHit, 0);
|
||||
|
||||
reserve(nNewLen);
|
||||
// we have to grow the buffer
|
||||
if ( capacity() < nNewLen ) {
|
||||
// allocation failure handled by caller
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
STATISTICS_ADD(ConcatHit, 1);
|
||||
|
||||
// the buffer is already big enough
|
||||
}
|
||||
|
||||
// should be enough space
|
||||
wxASSERT( nNewLen <= GetStringData()->nAllocLength );
|
||||
|
||||
// fast concatenation - all is done in our buffer
|
||||
memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxStringCharType));
|
||||
|
||||
m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
|
||||
GetStringData()->nDataLength = nNewLen; // and fix the length
|
||||
}
|
||||
//else: the string to append was empty
|
||||
return true;
|
||||
}
|
||||
|
||||
// get the pointer to writable buffer of (at least) nLen bytes
|
||||
wxStringCharType *wxStringImpl::DoGetWriteBuf(size_t nLen)
|
||||
{
|
||||
if ( !AllocBeforeWrite(nLen) ) {
|
||||
// allocation failure handled by caller
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wxASSERT( GetStringData()->nRefs == 1 );
|
||||
GetStringData()->Validate(false);
|
||||
|
||||
return m_pchData;
|
||||
}
|
||||
|
||||
// put string back in a reasonable state after GetWriteBuf
|
||||
void wxStringImpl::DoUngetWriteBuf()
|
||||
{
|
||||
DoUngetWriteBuf(wxStrlen(m_pchData));
|
||||
}
|
||||
|
||||
void wxStringImpl::DoUngetWriteBuf(size_t nLen)
|
||||
{
|
||||
wxStringData * const pData = GetStringData();
|
||||
|
||||
wxASSERT_MSG( nLen < pData->nAllocLength, wxT("buffer overrun") );
|
||||
|
||||
// the strings we store are always NUL-terminated
|
||||
pData->data()[nLen] = wxT('\0');
|
||||
pData->nDataLength = nLen;
|
||||
pData->Validate(true);
|
||||
}
|
||||
|
||||
#endif // !wxUSE_STL_BASED_WXSTRING
|
||||
@@ -0,0 +1,351 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/stringops.cpp
|
||||
// Purpose: implementation of wxString primitive operations
|
||||
// Author: Vaclav Slavik
|
||||
// Modified by:
|
||||
// Created: 2007-04-16
|
||||
// Copyright: (c) 2007 REA Elektronik GmbH
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ===========================================================================
|
||||
// headers
|
||||
// ===========================================================================
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/stringops.h"
|
||||
#endif
|
||||
|
||||
#include "wx/private/unicode.h"
|
||||
|
||||
// ===========================================================================
|
||||
// implementation
|
||||
// ===========================================================================
|
||||
|
||||
#if wxUSE_UNICODE_WCHAR || !wxUSE_UNICODE
|
||||
|
||||
#if wxUSE_UNICODE_UTF16
|
||||
|
||||
wxStringOperationsWchar::Utf16CharBuffer wxStringOperationsWchar::EncodeChar(const wxUniChar& ch)
|
||||
{
|
||||
Utf16CharBuffer buf;
|
||||
if ( ch.IsSupplementary() )
|
||||
{
|
||||
buf.data[0] = (wchar_t)ch.HighSurrogate();
|
||||
buf.data[1] = (wchar_t)ch.LowSurrogate();
|
||||
buf.data[2] = L'\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume ch is a BMP character
|
||||
buf.data[0] = (wchar_t)ch;
|
||||
buf.data[1] = L'\0';
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
wxWCharBuffer wxStringOperationsWchar::EncodeNChars(size_t n, const wxUniChar& ch)
|
||||
{
|
||||
if ( ch.IsSupplementary() )
|
||||
{
|
||||
wxWCharBuffer buf(n * 2);
|
||||
wchar_t s[2] = {
|
||||
(wchar_t)ch.HighSurrogate(),
|
||||
(wchar_t)ch.LowSurrogate(),
|
||||
};
|
||||
wchar_t *ptr = buf.data();
|
||||
for (size_t i = 0; i < n; i++, ptr += 2)
|
||||
{
|
||||
wmemcpy(ptr, s, 2);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume ch is a BMP character
|
||||
wxWCharBuffer buf(n);
|
||||
wmemset(buf.data(), (wchar_t)ch, n);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
wxWxCharBuffer wxStringOperationsWchar::EncodeNChars(size_t n, const wxUniChar& ch)
|
||||
{
|
||||
wxWxCharBuffer buf(n);
|
||||
#if wxUSE_UNICODE_WCHAR
|
||||
wmemset(buf.data(), (wchar_t)ch, n);
|
||||
#else // ANSI
|
||||
memset(buf.data(), (unsigned char)ch, n);
|
||||
#endif
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif // wxUSE_UNICODE_UTF16
|
||||
|
||||
#endif // wxUSE_UNICODE_WCHAR || !wxUSE_UNICODE
|
||||
|
||||
#if wxUSE_UNICODE_UTF8
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// UTF-8 sequences lengths
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
unsigned char wxStringOperationsUtf8::GetUTF8IterOffset(unsigned char c)
|
||||
{
|
||||
unsigned char l = tableUtf8Lengths[c];
|
||||
if ( !l ) //skip over invalid characters
|
||||
l = 1;
|
||||
return l;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// UTF-8 operations
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// Table 3.1B from Unicode spec: Legal UTF-8 Byte Sequences
|
||||
//
|
||||
// Code Points | 1st Byte | 2nd Byte | 3rd Byte | 4th Byte |
|
||||
// -------------------+----------+----------+----------+----------+
|
||||
// U+0000..U+007F | 00..7F | | | |
|
||||
// U+0080..U+07FF | C2..DF | 80..BF | | |
|
||||
// U+0800..U+0FFF | E0 | A0..BF | 80..BF | |
|
||||
// U+1000..U+FFFF | E1..EF | 80..BF | 80..BF | |
|
||||
// U+10000..U+3FFFF | F0 | 90..BF | 80..BF | 80..BF |
|
||||
// U+40000..U+FFFFF | F1..F3 | 80..BF | 80..BF | 80..BF |
|
||||
// U+100000..U+10FFFF | F4 | 80..8F | 80..BF | 80..BF |
|
||||
// -------------------+----------+----------+----------+----------+
|
||||
|
||||
bool wxStringOperationsUtf8::IsValidUtf8String(const char *str, size_t len)
|
||||
{
|
||||
if ( !str )
|
||||
return true; // empty string is UTF8 string
|
||||
|
||||
const unsigned char *c = (const unsigned char*)str;
|
||||
const unsigned char * const end = (len == wxStringImpl::npos) ? NULL : c + len;
|
||||
|
||||
for ( ; end != NULL ? c != end : *c; ++c )
|
||||
{
|
||||
unsigned char b = *c;
|
||||
|
||||
if ( end != NULL )
|
||||
{
|
||||
// if the string is not NULL-terminated, verify we have enough
|
||||
// bytes in it left for current character's encoding:
|
||||
if ( c + GetUTF8IterOffset(*c) > end )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( b <= 0x7F ) // 00..7F
|
||||
continue;
|
||||
|
||||
else if ( b < 0xC2 ) // invalid lead bytes: 80..C1
|
||||
return false;
|
||||
|
||||
// two-byte sequences:
|
||||
else if ( b <= 0xDF ) // C2..DF
|
||||
{
|
||||
b = *(++c);
|
||||
if ( !(b >= 0x80 && b <= 0xBF ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
// three-byte sequences:
|
||||
else if ( b == 0xE0 )
|
||||
{
|
||||
b = *(++c);
|
||||
if ( !(b >= 0xA0 && b <= 0xBF ) )
|
||||
return false;
|
||||
b = *(++c);
|
||||
if ( !(b >= 0x80 && b <= 0xBF ) )
|
||||
return false;
|
||||
}
|
||||
else if ( b == 0xED )
|
||||
{
|
||||
b = *(++c);
|
||||
if ( !(b >= 0x80 && b <= 0x9F ) )
|
||||
return false;
|
||||
b = *(++c);
|
||||
if ( !(b >= 0x80 && b <= 0xBF ) )
|
||||
return false;
|
||||
}
|
||||
else if ( b <= 0xEF ) // E1..EC EE..EF
|
||||
{
|
||||
for ( int i = 0; i < 2; ++i )
|
||||
{
|
||||
b = *(++c);
|
||||
if ( !(b >= 0x80 && b <= 0xBF ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// four-byte sequences:
|
||||
else if ( b == 0xF0 )
|
||||
{
|
||||
b = *(++c);
|
||||
if ( !(b >= 0x90 && b <= 0xBF ) )
|
||||
return false;
|
||||
for ( int i = 0; i < 2; ++i )
|
||||
{
|
||||
b = *(++c);
|
||||
if ( !(b >= 0x80 && b <= 0xBF ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( b <= 0xF3 ) // F1..F3
|
||||
{
|
||||
for ( int i = 0; i < 3; ++i )
|
||||
{
|
||||
b = *(++c);
|
||||
if ( !(b >= 0x80 && b <= 0xBF ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( b == 0xF4 )
|
||||
{
|
||||
b = *(++c);
|
||||
if ( !(b >= 0x80 && b <= 0x8F ) )
|
||||
return false;
|
||||
for ( int i = 0; i < 2; ++i )
|
||||
{
|
||||
b = *(++c);
|
||||
if ( !(b >= 0x80 && b <= 0xBF ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else // otherwise, it's invalid lead byte
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NB: this is in this file and not unichar.cpp to keep all UTF-8 encoding
|
||||
// code in single place
|
||||
wxUniChar::Utf8CharBuffer wxUniChar::AsUTF8() const
|
||||
{
|
||||
Utf8CharBuffer buf = { "" }; // init to avoid g++ 4.1 warning with -O2
|
||||
char *out = buf.data;
|
||||
|
||||
value_type code = GetValue();
|
||||
|
||||
// Char. number range | UTF-8 octet sequence
|
||||
// (hexadecimal) | (binary)
|
||||
// ----------------------+---------------------------------------------
|
||||
// 0000 0000 - 0000 007F | 0xxxxxxx
|
||||
// 0000 0080 - 0000 07FF | 110xxxxx 10xxxxxx
|
||||
// 0000 0800 - 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
|
||||
// 0001 0000 - 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
//
|
||||
// Code point value is stored in bits marked with 'x', lowest-order bit
|
||||
// of the value on the right side in the diagram above.
|
||||
// (from RFC 3629)
|
||||
|
||||
if ( code <= 0x7F )
|
||||
{
|
||||
out[1] = 0;
|
||||
out[0] = (char)code;
|
||||
}
|
||||
else if ( code <= 0x07FF )
|
||||
{
|
||||
out[2] = 0;
|
||||
// NB: this line takes 6 least significant bits, encodes them as
|
||||
// 10xxxxxx and discards them so that the next byte can be encoded:
|
||||
out[1] = 0x80 | (code & 0x3F); code >>= 6;
|
||||
out[0] = 0xC0 | code;
|
||||
}
|
||||
else if ( code < 0xFFFF )
|
||||
{
|
||||
out[3] = 0;
|
||||
out[2] = 0x80 | (code & 0x3F); code >>= 6;
|
||||
out[1] = 0x80 | (code & 0x3F); code >>= 6;
|
||||
out[0] = 0xE0 | code;
|
||||
}
|
||||
else if ( code <= 0x10FFFF )
|
||||
{
|
||||
out[4] = 0;
|
||||
out[3] = 0x80 | (code & 0x3F); code >>= 6;
|
||||
out[2] = 0x80 | (code & 0x3F); code >>= 6;
|
||||
out[1] = 0x80 | (code & 0x3F); code >>= 6;
|
||||
out[0] = 0xF0 | code;
|
||||
}
|
||||
else
|
||||
{
|
||||
wxFAIL_MSG( wxT("trying to encode undefined Unicode character") );
|
||||
out[0] = 0;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
wxUniChar
|
||||
wxStringOperationsUtf8::DecodeNonAsciiChar(wxStringImpl::const_iterator i)
|
||||
{
|
||||
wxASSERT( IsValidUtf8LeadByte(*i) );
|
||||
|
||||
size_t len = GetUtf8CharLength(*i);
|
||||
wxASSERT_MSG( len <= 4, wxT("invalid UTF-8 sequence length") );
|
||||
|
||||
// Char. number range | UTF-8 octet sequence
|
||||
// (hexadecimal) | (binary)
|
||||
// ----------------------+---------------------------------------------
|
||||
// 0000 0000 - 0000 007F | 0xxxxxxx
|
||||
// 0000 0080 - 0000 07FF | 110xxxxx 10xxxxxx
|
||||
// 0000 0800 - 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
|
||||
// 0001 0000 - 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
//
|
||||
// Code point value is stored in bits marked with 'x', lowest-order bit
|
||||
// of the value on the right side in the diagram above.
|
||||
// (from RFC 3629)
|
||||
|
||||
// mask to extract lead byte's value ('x' bits above), by sequence's length:
|
||||
static const unsigned char s_leadValueMask[4] = { 0x7F, 0x1F, 0x0F, 0x07 };
|
||||
#if wxDEBUG_LEVEL
|
||||
// mask and value of lead byte's most significant bits, by length:
|
||||
static const unsigned char s_leadMarkerMask[4] = { 0x80, 0xE0, 0xF0, 0xF8 };
|
||||
static const unsigned char s_leadMarkerVal[4] = { 0x00, 0xC0, 0xE0, 0xF0 };
|
||||
#endif
|
||||
|
||||
// extract the lead byte's value bits:
|
||||
wxASSERT_MSG( ((unsigned char)*i & s_leadMarkerMask[len-1]) ==
|
||||
s_leadMarkerVal[len-1],
|
||||
wxT("invalid UTF-8 lead byte") );
|
||||
wxUniChar::value_type code = (unsigned char)*i & s_leadValueMask[len-1];
|
||||
|
||||
// all remaining bytes, if any, are handled in the same way regardless of
|
||||
// sequence's length:
|
||||
for ( ++i ; len > 1; --len, ++i )
|
||||
{
|
||||
wxASSERT_MSG( ((unsigned char)*i & 0xC0) == 0x80,
|
||||
wxT("invalid UTF-8 byte") );
|
||||
|
||||
code <<= 6;
|
||||
code |= (unsigned char)*i & 0x3F;
|
||||
}
|
||||
|
||||
return wxUniChar(code);
|
||||
}
|
||||
|
||||
wxCharBuffer wxStringOperationsUtf8::EncodeNChars(size_t n, const wxUniChar& ch)
|
||||
{
|
||||
Utf8CharBuffer once(EncodeChar(ch));
|
||||
// the IncIter() table can be used to determine the length of ch's encoding:
|
||||
size_t len = GetUTF8IterOffset(once.data[0]);
|
||||
|
||||
wxCharBuffer buf(n * len);
|
||||
char *ptr = buf.data();
|
||||
for ( size_t i = 0; i < n; i++, ptr += len )
|
||||
{
|
||||
memcpy(ptr, once.data, len);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif // wxUSE_UNICODE_UTF8
|
||||
@@ -0,0 +1,771 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/strvararg.cpp
|
||||
// Purpose: macros for implementing type-safe vararg passing of strings
|
||||
// Author: Vaclav Slavik
|
||||
// Created: 2007-02-19
|
||||
// Copyright: (c) 2007 REA Elektronik GmbH
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// for compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#include "wx/strvararg.h"
|
||||
#include "wx/string.h"
|
||||
#include "wx/crt.h"
|
||||
#include "wx/private/wxprintf.h"
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxArgNormalizer<>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const wxStringCharType *wxArgNormalizerNative<const wxString&>::get() const
|
||||
{
|
||||
return m_value.wx_str();
|
||||
}
|
||||
|
||||
const wxStringCharType *wxArgNormalizerNative<const wxCStrData&>::get() const
|
||||
{
|
||||
return m_value.AsInternal();
|
||||
}
|
||||
|
||||
#if wxUSE_UNICODE_UTF8 && !wxUSE_UTF8_LOCALE_ONLY
|
||||
wxArgNormalizerWchar<const wxString&>::wxArgNormalizerWchar(
|
||||
const wxString& s,
|
||||
const wxFormatString *fmt, unsigned index)
|
||||
: wxArgNormalizerWithBuffer<wchar_t>(s.wc_str(), fmt, index)
|
||||
{
|
||||
}
|
||||
|
||||
wxArgNormalizerWchar<const wxCStrData&>::wxArgNormalizerWchar(
|
||||
const wxCStrData& s,
|
||||
const wxFormatString *fmt, unsigned index)
|
||||
: wxArgNormalizerWithBuffer<wchar_t>(s.AsWCharBuf(), fmt, index)
|
||||
{
|
||||
}
|
||||
#endif // wxUSE_UNICODE_UTF8 && !wxUSE_UTF8_LOCALE_ONLY
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxArgNormalizedString
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxString wxArgNormalizedString::GetString() const
|
||||
{
|
||||
if ( !IsValid() )
|
||||
return wxEmptyString;
|
||||
|
||||
#if wxUSE_UTF8_LOCALE_ONLY
|
||||
return wxString(reinterpret_cast<const char*>(m_ptr));
|
||||
#else
|
||||
#if wxUSE_UNICODE_UTF8
|
||||
if ( wxLocaleIsUtf8 )
|
||||
return wxString(reinterpret_cast<const char*>(m_ptr));
|
||||
else
|
||||
#endif
|
||||
return wxString(reinterpret_cast<const wxChar*>(m_ptr));
|
||||
#endif // !wxUSE_UTF8_LOCALE_ONLY
|
||||
}
|
||||
|
||||
wxArgNormalizedString::operator wxString() const
|
||||
{
|
||||
return GetString();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFormatConverter: class doing the "%s" and "%c" normalization
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
There are four problems with wxPrintf() etc. format strings:
|
||||
|
||||
1) The printf vararg macros convert all forms of strings into
|
||||
wxStringCharType* representation. This may make the format string
|
||||
incorrect: for example, if %ls was used together with a wchar_t*
|
||||
variadic argument, this would no longer work, because the templates
|
||||
would change wchar_t* argument to wxStringCharType* and %ls would now
|
||||
be incorrect in e.g. UTF-8 build. We need make sure only one specifier
|
||||
form is used.
|
||||
|
||||
2) To complicate matters further, the meaning of %s and %c is different
|
||||
under Windows and on Unix. The Windows/MS convention is as follows:
|
||||
|
||||
In ANSI mode:
|
||||
|
||||
format specifier results in
|
||||
-----------------------------------
|
||||
%s, %hs, %hS char*
|
||||
%ls, %S, %lS wchar_t*
|
||||
|
||||
In Unicode mode:
|
||||
|
||||
format specifier results in
|
||||
-----------------------------------
|
||||
%hs, %S, %hS char*
|
||||
%s, %ls, %lS wchar_t*
|
||||
|
||||
(While on POSIX systems we have %C identical to %lc and %c always means
|
||||
char (in any mode) while %lc always means wchar_t.)
|
||||
|
||||
In other words, we should _only_ use %s on Windows and %ls on Unix for
|
||||
wxUSE_UNICODE_WCHAR build.
|
||||
|
||||
3) To make things even worse, we need two forms in UTF-8 build: one for
|
||||
passing strings to ANSI functions under UTF-8 locales (this one should
|
||||
use %s) and one for widechar functions used under non-UTF-8 locales
|
||||
(this one should use %ls).
|
||||
|
||||
And, of course, the same should be done for %c as well.
|
||||
|
||||
|
||||
wxScanf() family of functions is simpler, because we don't normalize their
|
||||
variadic arguments and we only have to handle 2) above and only for widechar
|
||||
versions.
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
class wxFormatConverterBase
|
||||
{
|
||||
public:
|
||||
typedef T CharType;
|
||||
|
||||
wxFormatConverterBase()
|
||||
{
|
||||
m_fmtOrig = NULL;
|
||||
m_fmtLast = NULL;
|
||||
m_nCopied = 0;
|
||||
}
|
||||
|
||||
wxScopedCharTypeBuffer<CharType> Convert(const CharType *format)
|
||||
{
|
||||
// this is reset to NULL if we modify the format string
|
||||
m_fmtOrig = format;
|
||||
|
||||
while ( *format )
|
||||
{
|
||||
if ( CopyFmtChar(*format++) == wxT('%') )
|
||||
{
|
||||
#if wxUSE_PRINTF_POS_PARAMS
|
||||
if ( *format >= '0' && *format <= '9' )
|
||||
{
|
||||
SkipDigits(&format);
|
||||
if ( *format == '$' )
|
||||
{
|
||||
// It was a positional argument specification.
|
||||
CopyFmtChar(*format++);
|
||||
}
|
||||
//else: it was a width specification, nothing else to do.
|
||||
}
|
||||
#endif // wxUSE_PRINTF_POS_PARAMS
|
||||
|
||||
// skip any flags
|
||||
while ( IsFlagChar(*format) )
|
||||
CopyFmtChar(*format++);
|
||||
|
||||
// and possible width
|
||||
if ( *format == wxT('*') )
|
||||
CopyFmtChar(*format++);
|
||||
else
|
||||
SkipDigits(&format);
|
||||
|
||||
// precision?
|
||||
if ( *format == wxT('.') )
|
||||
{
|
||||
CopyFmtChar(*format++);
|
||||
if ( *format == wxT('*') )
|
||||
CopyFmtChar(*format++);
|
||||
else
|
||||
SkipDigits(&format);
|
||||
}
|
||||
|
||||
// next we can have a size modifier
|
||||
SizeModifier size;
|
||||
|
||||
switch ( *format )
|
||||
{
|
||||
// MSVC doesn't support C99 'z' size modifier, but it uses
|
||||
// 'I' with exactly the same meaning.
|
||||
//
|
||||
// MinGW does support 'z' but only in ANSI stdio mode, and
|
||||
// we can't be sure that this is what is actually going to
|
||||
// be used, application code could explicitly define
|
||||
// __USE_MINGW_ANSI_STDIO=0 (e.g. because it needs legacy
|
||||
// behaviour for its own printf() calls), so we map it to
|
||||
// 'I' for it too.
|
||||
#if defined(__VISUALC__) || defined(__MINGW32__)
|
||||
case 'z':
|
||||
ChangeFmtChar('I');
|
||||
format++;
|
||||
size = Size_Default;
|
||||
break;
|
||||
#endif // __VISUALC__ || __MINGW32__
|
||||
|
||||
case 'h':
|
||||
size = Size_Short;
|
||||
format++;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
// "ll" has a different meaning!
|
||||
if ( format[1] != 'l' )
|
||||
{
|
||||
size = Size_Long;
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
wxFALLTHROUGH;
|
||||
|
||||
default:
|
||||
size = Size_Default;
|
||||
}
|
||||
|
||||
CharType outConv = *format;
|
||||
SizeModifier outSize = size;
|
||||
|
||||
// and finally we should have the type
|
||||
switch ( *format )
|
||||
{
|
||||
case wxT('S'):
|
||||
case wxT('s'):
|
||||
// all strings were converted into the same form by
|
||||
// wxArgNormalizer<T>, this form depends on the context
|
||||
// in which the value is used (scanf/printf/wprintf):
|
||||
HandleString(*format, size, outConv, outSize);
|
||||
break;
|
||||
|
||||
case wxT('C'):
|
||||
case wxT('c'):
|
||||
HandleChar(*format, size, outConv, outSize);
|
||||
break;
|
||||
|
||||
default:
|
||||
// nothing special to do
|
||||
break;
|
||||
}
|
||||
|
||||
if ( outConv == *format && outSize == size ) // no change
|
||||
{
|
||||
if ( size != Size_Default )
|
||||
CopyFmtChar(*(format - 1));
|
||||
CopyFmtChar(*format);
|
||||
}
|
||||
else // something changed
|
||||
{
|
||||
switch ( outSize )
|
||||
{
|
||||
case Size_Long:
|
||||
InsertFmtChar(wxT('l'));
|
||||
break;
|
||||
|
||||
case Size_Short:
|
||||
InsertFmtChar(wxT('h'));
|
||||
break;
|
||||
|
||||
case Size_Default:
|
||||
// nothing to do
|
||||
break;
|
||||
}
|
||||
InsertFmtChar(outConv);
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
// notice that we only translated the string if m_fmtOrig == NULL (as
|
||||
// set by CopyAllBefore()), otherwise we should simply use the original
|
||||
// format
|
||||
if ( m_fmtOrig )
|
||||
{
|
||||
return wxScopedCharTypeBuffer<CharType>::CreateNonOwned(m_fmtOrig);
|
||||
}
|
||||
else
|
||||
{
|
||||
// shrink converted format string to actual size (instead of
|
||||
// over-sized allocation from CopyAllBefore()) and NUL-terminate
|
||||
// it:
|
||||
m_fmt.shrink(m_fmtLast - m_fmt.data());
|
||||
return m_fmt;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~wxFormatConverterBase() {}
|
||||
|
||||
protected:
|
||||
enum SizeModifier
|
||||
{
|
||||
Size_Default,
|
||||
Size_Short,
|
||||
Size_Long
|
||||
};
|
||||
|
||||
// called to handle %S or %s; 'conv' is conversion specifier ('S' or 's'
|
||||
// respectively), 'size' is the preceding size modifier; the new values of
|
||||
// conversion and size specifiers must be written to outConv and outSize
|
||||
virtual void HandleString(CharType conv, SizeModifier size,
|
||||
CharType& outConv, SizeModifier& outSize) = 0;
|
||||
|
||||
// ditto for %C or %c
|
||||
virtual void HandleChar(CharType conv, SizeModifier size,
|
||||
CharType& outConv, SizeModifier& outSize) = 0;
|
||||
|
||||
private:
|
||||
// copy another character to the translated format: this function does the
|
||||
// copy if we are translating but doesn't do anything at all if we don't,
|
||||
// so we don't create the translated format string at all unless we really
|
||||
// need to (i.e. InsertFmtChar() is called)
|
||||
CharType CopyFmtChar(CharType ch)
|
||||
{
|
||||
if ( !m_fmtOrig )
|
||||
{
|
||||
// we're translating, do copy
|
||||
*(m_fmtLast++) = ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
// simply increase the count which should be copied by
|
||||
// CopyAllBefore() later if needed
|
||||
m_nCopied++;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
// insert an extra character
|
||||
void InsertFmtChar(CharType ch)
|
||||
{
|
||||
if ( m_fmtOrig )
|
||||
{
|
||||
// so far we haven't translated anything yet
|
||||
CopyAllBefore();
|
||||
}
|
||||
|
||||
*(m_fmtLast++) = ch;
|
||||
}
|
||||
|
||||
// change a character
|
||||
void ChangeFmtChar(CharType ch)
|
||||
{
|
||||
if ( m_fmtOrig )
|
||||
{
|
||||
// so far we haven't translated anything yet
|
||||
CopyAllBefore();
|
||||
}
|
||||
|
||||
*m_fmtLast++ = ch;
|
||||
}
|
||||
|
||||
void CopyAllBefore()
|
||||
{
|
||||
wxASSERT_MSG( m_fmtOrig && m_fmt.data() == NULL, "logic error" );
|
||||
|
||||
// the modified format string is guaranteed to be no longer than
|
||||
// 3/2 of the original (worst case: the entire format string consists
|
||||
// of "%s" repeated and is expanded to "%ls" on Unix), so we can
|
||||
// allocate the buffer now and not worry about running out of space if
|
||||
// we over-allocate a bit:
|
||||
size_t fmtLen = wxStrlen(m_fmtOrig);
|
||||
// worst case is of even length, so there's no rounding error in *3/2:
|
||||
m_fmt.extend(fmtLen * 3 / 2);
|
||||
|
||||
if ( m_nCopied > 0 )
|
||||
wxStrncpy(m_fmt.data(), m_fmtOrig, m_nCopied);
|
||||
m_fmtLast = m_fmt.data() + m_nCopied;
|
||||
|
||||
// we won't need it any longer and resetting it also indicates that we
|
||||
// modified the format
|
||||
m_fmtOrig = NULL;
|
||||
}
|
||||
|
||||
static bool IsFlagChar(CharType ch)
|
||||
{
|
||||
return ch == wxT('-') || ch == wxT('+') ||
|
||||
ch == wxT('0') || ch == wxT(' ') || ch == wxT('#');
|
||||
}
|
||||
|
||||
void SkipDigits(const CharType **ptpc)
|
||||
{
|
||||
while ( **ptpc >= wxT('0') && **ptpc <= wxT('9') )
|
||||
CopyFmtChar(*(*ptpc)++);
|
||||
}
|
||||
|
||||
// the translated format
|
||||
wxCharTypeBuffer<CharType> m_fmt;
|
||||
CharType *m_fmtLast;
|
||||
|
||||
// the original format
|
||||
const CharType *m_fmtOrig;
|
||||
|
||||
// the number of characters already copied (i.e. already parsed, but left
|
||||
// unmodified)
|
||||
size_t m_nCopied;
|
||||
};
|
||||
|
||||
// Distinguish between the traditional Windows (and MSVC) behaviour and Cygwin
|
||||
// (which is always Unix-like) and MinGW. The last one is the most interesting
|
||||
// case as it can behave either as MSVC (__USE_MINGW_ANSI_STDIO=0) or as POSIX
|
||||
// (__USE_MINGW_ANSI_STDIO=1, which is explicitly set by including any standard
|
||||
// C++ header such as e.g. <string>). Luckily, "%ls" and "%lc" work in both
|
||||
// cases, at least for recent MinGW versions, so just use it always.
|
||||
#if defined(__WINDOWS__) && \
|
||||
!defined(__CYGWIN__) && \
|
||||
!defined(__MINGW32__)
|
||||
|
||||
// on Windows, we should use %s and %c regardless of the build:
|
||||
class wxPrintfFormatConverterWchar : public wxFormatConverterBase<wchar_t>
|
||||
{
|
||||
virtual void HandleString(CharType WXUNUSED(conv),
|
||||
SizeModifier WXUNUSED(size),
|
||||
CharType& outConv, SizeModifier& outSize)
|
||||
{
|
||||
outConv = 's';
|
||||
outSize = Size_Default;
|
||||
}
|
||||
|
||||
virtual void HandleChar(CharType WXUNUSED(conv),
|
||||
SizeModifier WXUNUSED(size),
|
||||
CharType& outConv, SizeModifier& outSize)
|
||||
{
|
||||
outConv = 'c';
|
||||
outSize = Size_Default;
|
||||
}
|
||||
};
|
||||
|
||||
#else // !__WINDOWS__
|
||||
|
||||
// on Unix, it's %s for ANSI functions and %ls for widechar:
|
||||
|
||||
#if !wxUSE_UTF8_LOCALE_ONLY
|
||||
class wxPrintfFormatConverterWchar : public wxFormatConverterBase<wchar_t>
|
||||
{
|
||||
virtual void HandleString(CharType WXUNUSED(conv),
|
||||
SizeModifier WXUNUSED(size),
|
||||
CharType& outConv, SizeModifier& outSize) wxOVERRIDE
|
||||
{
|
||||
outConv = 's';
|
||||
outSize = Size_Long;
|
||||
}
|
||||
|
||||
virtual void HandleChar(CharType WXUNUSED(conv),
|
||||
SizeModifier WXUNUSED(size),
|
||||
CharType& outConv, SizeModifier& outSize) wxOVERRIDE
|
||||
{
|
||||
outConv = 'c';
|
||||
outSize = Size_Long;
|
||||
}
|
||||
};
|
||||
#endif // !wxUSE_UTF8_LOCALE_ONLY
|
||||
|
||||
#endif // __WINDOWS__/!__WINDOWS__
|
||||
|
||||
#if wxUSE_UNICODE_UTF8
|
||||
class wxPrintfFormatConverterUtf8 : public wxFormatConverterBase<char>
|
||||
{
|
||||
virtual void HandleString(CharType WXUNUSED(conv),
|
||||
SizeModifier WXUNUSED(size),
|
||||
CharType& outConv, SizeModifier& outSize) wxOVERRIDE
|
||||
{
|
||||
outConv = 's';
|
||||
outSize = Size_Default;
|
||||
}
|
||||
|
||||
virtual void HandleChar(CharType WXUNUSED(conv),
|
||||
SizeModifier WXUNUSED(size),
|
||||
CharType& outConv, SizeModifier& outSize) wxOVERRIDE
|
||||
{
|
||||
// chars are represented using wchar_t in both builds, so this is
|
||||
// the same as above
|
||||
outConv = 'c';
|
||||
outSize = Size_Long;
|
||||
}
|
||||
};
|
||||
#endif // wxUSE_UNICODE_UTF8
|
||||
|
||||
#if !wxUSE_UNICODE // FIXME-UTF8: remove
|
||||
class wxPrintfFormatConverterANSI : public wxFormatConverterBase<char>
|
||||
{
|
||||
virtual void HandleString(CharType WXUNUSED(conv),
|
||||
SizeModifier WXUNUSED(size),
|
||||
CharType& outConv, SizeModifier& outSize)
|
||||
{
|
||||
outConv = 's';
|
||||
outSize = Size_Default;
|
||||
}
|
||||
|
||||
virtual void HandleChar(CharType WXUNUSED(conv),
|
||||
SizeModifier WXUNUSED(size),
|
||||
CharType& outConv, SizeModifier& outSize)
|
||||
{
|
||||
outConv = 'c';
|
||||
outSize = Size_Default;
|
||||
}
|
||||
};
|
||||
#endif // ANSI
|
||||
|
||||
#ifndef __WINDOWS__
|
||||
/*
|
||||
|
||||
wxScanf() format translation is different, we need to translate %s to %ls
|
||||
and %c to %lc on Unix (but not Windows and for widechar functions only!).
|
||||
|
||||
So to use native functions in order to get our semantics we must do the
|
||||
following translations in Unicode mode:
|
||||
|
||||
wxWidgets specifier POSIX specifier
|
||||
----------------------------------------
|
||||
|
||||
%hc, %C, %hC %c
|
||||
%c %lc
|
||||
|
||||
*/
|
||||
class wxScanfFormatConverterWchar : public wxFormatConverterBase<wchar_t>
|
||||
{
|
||||
virtual void HandleString(CharType conv, SizeModifier size,
|
||||
CharType& outConv, SizeModifier& outSize) wxOVERRIDE
|
||||
{
|
||||
outConv = 's';
|
||||
outSize = GetOutSize(conv == 'S', size);
|
||||
}
|
||||
|
||||
virtual void HandleChar(CharType conv, SizeModifier size,
|
||||
CharType& outConv, SizeModifier& outSize) wxOVERRIDE
|
||||
{
|
||||
outConv = 'c';
|
||||
outSize = GetOutSize(conv == 'C', size);
|
||||
}
|
||||
|
||||
SizeModifier GetOutSize(bool convIsUpper, SizeModifier size)
|
||||
{
|
||||
// %S and %hS -> %s and %lS -> %ls
|
||||
if ( convIsUpper )
|
||||
{
|
||||
if ( size == Size_Long )
|
||||
return Size_Long;
|
||||
else
|
||||
return Size_Default;
|
||||
}
|
||||
else // %s or %c
|
||||
{
|
||||
if ( size == Size_Default )
|
||||
return Size_Long;
|
||||
else
|
||||
return size;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const wxScopedWCharBuffer wxScanfConvertFormatW(const wchar_t *format)
|
||||
{
|
||||
return wxScanfFormatConverterWchar().Convert(format);
|
||||
}
|
||||
#endif // !__WINDOWS__
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFormatString
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if !wxUSE_UNICODE_WCHAR
|
||||
const char* wxFormatString::InputAsChar()
|
||||
{
|
||||
if ( m_char )
|
||||
return m_char.data();
|
||||
|
||||
// in ANSI build, wx_str() returns char*, in UTF-8 build, this function
|
||||
// is only called under UTF-8 locales, so we should return UTF-8 string,
|
||||
// which is, again, what wx_str() returns:
|
||||
if ( m_str )
|
||||
return m_str->wx_str();
|
||||
|
||||
// ditto wxCStrData:
|
||||
if ( m_cstr )
|
||||
return m_cstr->AsInternal();
|
||||
|
||||
// the last case is that wide string was passed in: in that case, we need
|
||||
// to convert it:
|
||||
wxASSERT( m_wchar );
|
||||
|
||||
m_char = wxConvLibc.cWC2MB(m_wchar.data());
|
||||
|
||||
return m_char.data();
|
||||
}
|
||||
|
||||
const char* wxFormatString::AsChar()
|
||||
{
|
||||
if ( !m_convertedChar )
|
||||
#if !wxUSE_UNICODE // FIXME-UTF8: remove this
|
||||
m_convertedChar = wxPrintfFormatConverterANSI().Convert(InputAsChar());
|
||||
#else
|
||||
m_convertedChar = wxPrintfFormatConverterUtf8().Convert(InputAsChar());
|
||||
#endif
|
||||
|
||||
return m_convertedChar.data();
|
||||
}
|
||||
#endif // !wxUSE_UNICODE_WCHAR
|
||||
|
||||
#if wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY
|
||||
const wchar_t* wxFormatString::InputAsWChar()
|
||||
{
|
||||
if ( m_wchar )
|
||||
return m_wchar.data();
|
||||
|
||||
#if wxUSE_UNICODE_WCHAR
|
||||
if ( m_str )
|
||||
return m_str->wc_str();
|
||||
if ( m_cstr )
|
||||
return m_cstr->AsInternal();
|
||||
#else // wxUSE_UNICODE_UTF8
|
||||
if ( m_str )
|
||||
{
|
||||
m_wchar = m_str->wc_str();
|
||||
return m_wchar.data();
|
||||
}
|
||||
if ( m_cstr )
|
||||
{
|
||||
m_wchar = m_cstr->AsWCharBuf();
|
||||
return m_wchar.data();
|
||||
}
|
||||
#endif // wxUSE_UNICODE_WCHAR/UTF8
|
||||
|
||||
// the last case is that narrow string was passed in: in that case, we need
|
||||
// to convert it:
|
||||
wxASSERT( m_char );
|
||||
|
||||
m_wchar = wxConvLibc.cMB2WC(m_char.data());
|
||||
|
||||
return m_wchar.data();
|
||||
}
|
||||
|
||||
const wchar_t* wxFormatString::AsWChar()
|
||||
{
|
||||
if ( !m_convertedWChar )
|
||||
m_convertedWChar = wxPrintfFormatConverterWchar().Convert(InputAsWChar());
|
||||
|
||||
return m_convertedWChar.data();
|
||||
}
|
||||
#endif // wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY
|
||||
|
||||
wxString wxFormatString::InputAsString() const
|
||||
{
|
||||
if ( m_str )
|
||||
return *m_str;
|
||||
if ( m_cstr )
|
||||
return m_cstr->AsString();
|
||||
if ( m_wchar )
|
||||
return wxString(m_wchar);
|
||||
if ( m_char )
|
||||
return wxString(m_char);
|
||||
|
||||
wxFAIL_MSG( "invalid wxFormatString - not initialized?" );
|
||||
return wxString();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxFormatString::GetArgumentType()
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template<typename CharType>
|
||||
wxFormatString::ArgumentType DoGetArgumentType(const CharType *format,
|
||||
unsigned n)
|
||||
{
|
||||
wxCHECK_MSG( format, wxFormatString::Arg_Unknown,
|
||||
"empty format string not allowed here" );
|
||||
|
||||
wxPrintfConvSpecParser<CharType> parser(format);
|
||||
|
||||
if ( n > parser.nargs )
|
||||
{
|
||||
// The n-th argument doesn't appear in the format string and is unused.
|
||||
// This can happen e.g. if a translation of the format string is used
|
||||
// and the translation language tends to avoid numbers in singular forms.
|
||||
// The translator would then typically replace "%d" with "One" (e.g. in
|
||||
// Hebrew). Passing too many vararg arguments does not harm, so its
|
||||
// better to be more permissive here and allow legitimate uses in favour
|
||||
// of catching harmless errors.
|
||||
return wxFormatString::Arg_Unused;
|
||||
}
|
||||
|
||||
wxCHECK_MSG( parser.pspec[n-1] != NULL, wxFormatString::Arg_Unknown,
|
||||
"requested argument not found - invalid format string?" );
|
||||
|
||||
switch ( parser.pspec[n-1]->m_type )
|
||||
{
|
||||
case wxPAT_CHAR:
|
||||
case wxPAT_WCHAR:
|
||||
return wxFormatString::Arg_Char;
|
||||
|
||||
case wxPAT_PCHAR:
|
||||
case wxPAT_PWCHAR:
|
||||
return wxFormatString::Arg_String;
|
||||
|
||||
case wxPAT_INT:
|
||||
return wxFormatString::Arg_Int;
|
||||
case wxPAT_LONGINT:
|
||||
return wxFormatString::Arg_LongInt;
|
||||
#ifdef wxLongLong_t
|
||||
case wxPAT_LONGLONGINT:
|
||||
return wxFormatString::Arg_LongLongInt;
|
||||
#endif
|
||||
case wxPAT_SIZET:
|
||||
return wxFormatString::Arg_Size_t;
|
||||
|
||||
case wxPAT_DOUBLE:
|
||||
return wxFormatString::Arg_Double;
|
||||
case wxPAT_LONGDOUBLE:
|
||||
return wxFormatString::Arg_LongDouble;
|
||||
|
||||
case wxPAT_POINTER:
|
||||
return wxFormatString::Arg_Pointer;
|
||||
|
||||
case wxPAT_NINT:
|
||||
return wxFormatString::Arg_IntPtr;
|
||||
case wxPAT_NSHORTINT:
|
||||
return wxFormatString::Arg_ShortIntPtr;
|
||||
case wxPAT_NLONGINT:
|
||||
return wxFormatString::Arg_LongIntPtr;
|
||||
|
||||
case wxPAT_STAR:
|
||||
// "*" requires argument of type int
|
||||
return wxFormatString::Arg_Int;
|
||||
|
||||
case wxPAT_INVALID:
|
||||
// (handled after the switch statement)
|
||||
break;
|
||||
}
|
||||
|
||||
// silence warning
|
||||
wxFAIL_MSG( "unexpected argument type" );
|
||||
return wxFormatString::Arg_Unknown;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
wxFormatString::ArgumentType wxFormatString::GetArgumentType(unsigned n) const
|
||||
{
|
||||
if ( m_char )
|
||||
return DoGetArgumentType(m_char.data(), n);
|
||||
else if ( m_wchar )
|
||||
return DoGetArgumentType(m_wchar.data(), n);
|
||||
else if ( m_str )
|
||||
return DoGetArgumentType(m_str->wx_str(), n);
|
||||
else if ( m_cstr )
|
||||
return DoGetArgumentType(m_cstr->AsInternal(), n);
|
||||
|
||||
wxFAIL_MSG( "unreachable code" );
|
||||
return Arg_Unknown;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/sysopt.cpp
|
||||
// Purpose: wxSystemOptions
|
||||
// Author: Julian Smart
|
||||
// Modified by:
|
||||
// Created: 2001-07-10
|
||||
// Copyright: (c) Julian Smart
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// headers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
|
||||
#if wxUSE_SYSTEM_OPTIONS
|
||||
|
||||
#include "wx/sysopt.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/app.h"
|
||||
#include "wx/list.h"
|
||||
#include "wx/string.h"
|
||||
#include "wx/arrstr.h"
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// private globals
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static wxArrayString gs_optionNames,
|
||||
gs_optionValues;
|
||||
|
||||
// ============================================================================
|
||||
// wxSystemOptions implementation
|
||||
// ============================================================================
|
||||
|
||||
// Option functions (arbitrary name/value mapping)
|
||||
void wxSystemOptions::SetOption(const wxString& name, const wxString& value)
|
||||
{
|
||||
int idx = gs_optionNames.Index(name, false);
|
||||
if (idx == wxNOT_FOUND)
|
||||
{
|
||||
gs_optionNames.Add(name);
|
||||
gs_optionValues.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
gs_optionNames[idx] = name;
|
||||
gs_optionValues[idx] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void wxSystemOptions::SetOption(const wxString& name, int value)
|
||||
{
|
||||
SetOption(name, wxString::Format(wxT("%d"), value));
|
||||
}
|
||||
|
||||
wxString wxSystemOptions::GetOption(const wxString& name)
|
||||
{
|
||||
wxString val;
|
||||
|
||||
int idx = gs_optionNames.Index(name, false);
|
||||
if ( idx != wxNOT_FOUND )
|
||||
{
|
||||
val = gs_optionValues[idx];
|
||||
}
|
||||
else // not set explicitly
|
||||
{
|
||||
// look in the environment: first for a variable named "wx_appname_name"
|
||||
// which can be set to affect the behaviour or just this application
|
||||
// and then for "wx_name" which can be set to change the option globally
|
||||
wxString var(name);
|
||||
var.Replace(wxT("."), wxT("_")); // '.'s not allowed in env var names
|
||||
var.Replace(wxT("-"), wxT("_")); // and neither are '-'s
|
||||
|
||||
wxString appname;
|
||||
if ( wxTheApp )
|
||||
appname = wxTheApp->GetAppName();
|
||||
|
||||
if ( !appname.empty() )
|
||||
val = wxGetenv(wxT("wx_") + appname + wxT('_') + var);
|
||||
|
||||
if ( val.empty() )
|
||||
val = wxGetenv(wxT("wx_") + var);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int wxSystemOptions::GetOptionInt(const wxString& name)
|
||||
{
|
||||
return wxAtoi (GetOption(name));
|
||||
}
|
||||
|
||||
bool wxSystemOptions::HasOption(const wxString& name)
|
||||
{
|
||||
return !GetOption(name).empty();
|
||||
}
|
||||
|
||||
#endif // wxUSE_SYSTEM_OPTIONS
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,270 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/common/textbuf.cpp
|
||||
// Purpose: implementation of wxTextBuffer class
|
||||
// Created: 14.11.01
|
||||
// Author: Morten Hanssen, Vadim Zeitlin
|
||||
// Copyright: (c) 1998-2001 wxWidgets team
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// headers
|
||||
// ============================================================================
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/string.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/log.h"
|
||||
#endif
|
||||
|
||||
#include "wx/textbuf.h"
|
||||
|
||||
// ============================================================================
|
||||
// wxTextBuffer class implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// static methods (always compiled in)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// default type is the native one
|
||||
|
||||
const wxTextFileType wxTextBuffer::typeDefault =
|
||||
#if defined(__WINDOWS__)
|
||||
wxTextFileType_Dos;
|
||||
#elif defined(__UNIX__)
|
||||
wxTextFileType_Unix;
|
||||
#else
|
||||
wxTextFileType_None;
|
||||
#error "wxTextBuffer: unsupported platform."
|
||||
#endif
|
||||
|
||||
const wxChar *wxTextBuffer::GetEOL(wxTextFileType type)
|
||||
{
|
||||
switch ( type ) {
|
||||
default:
|
||||
wxFAIL_MSG(wxT("bad buffer type in wxTextBuffer::GetEOL."));
|
||||
wxFALLTHROUGH; // fall through nevertheless - we must return something...
|
||||
|
||||
case wxTextFileType_None: return wxEmptyString;
|
||||
case wxTextFileType_Unix: return wxT("\n");
|
||||
case wxTextFileType_Dos: return wxT("\r\n");
|
||||
case wxTextFileType_Mac: return wxT("\r");
|
||||
}
|
||||
}
|
||||
|
||||
wxString wxTextBuffer::Translate(const wxString& text, wxTextFileType type)
|
||||
{
|
||||
// don't do anything if there is nothing to do
|
||||
if ( type == wxTextFileType_None )
|
||||
return text;
|
||||
|
||||
// nor if it is empty
|
||||
if ( text.empty() )
|
||||
return text;
|
||||
|
||||
wxString eol = GetEOL(type), result;
|
||||
|
||||
// optimization: we know that the length of the new string will be about
|
||||
// the same as the length of the old one, so prealloc memory to avoid
|
||||
// unnecessary relocations
|
||||
result.Alloc(text.Len());
|
||||
|
||||
wxChar chLast = 0;
|
||||
for ( wxString::const_iterator i = text.begin(); i != text.end(); ++i )
|
||||
{
|
||||
wxChar ch = *i;
|
||||
switch ( ch ) {
|
||||
case wxT('\n'):
|
||||
// Dos/Unix line termination
|
||||
result += eol;
|
||||
chLast = 0;
|
||||
break;
|
||||
|
||||
case wxT('\r'):
|
||||
if ( chLast == wxT('\r') ) {
|
||||
// Mac empty line
|
||||
result += eol;
|
||||
}
|
||||
else {
|
||||
// just remember it: we don't know whether it is just "\r"
|
||||
// or "\r\n" yet
|
||||
chLast = wxT('\r');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( chLast == wxT('\r') ) {
|
||||
// Mac line termination
|
||||
result += eol;
|
||||
|
||||
// reset chLast to avoid inserting another eol before the
|
||||
// next character
|
||||
chLast = 0;
|
||||
}
|
||||
|
||||
// add to the current line
|
||||
result += ch;
|
||||
}
|
||||
}
|
||||
|
||||
if ( chLast ) {
|
||||
// trailing '\r'
|
||||
result += eol;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if wxUSE_TEXTBUFFER
|
||||
|
||||
wxString wxTextBuffer::ms_eof;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ctors & dtor
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxTextBuffer::wxTextBuffer(const wxString& strBufferName)
|
||||
: m_strBufferName(strBufferName)
|
||||
{
|
||||
m_nCurLine = 0;
|
||||
m_isOpened = false;
|
||||
}
|
||||
|
||||
wxTextBuffer::~wxTextBuffer()
|
||||
{
|
||||
// required here for Darwin
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// buffer operations
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxTextBuffer::Exists() const
|
||||
{
|
||||
return OnExists();
|
||||
}
|
||||
|
||||
bool wxTextBuffer::Create(const wxString& strBufferName)
|
||||
{
|
||||
m_strBufferName = strBufferName;
|
||||
|
||||
return Create();
|
||||
}
|
||||
|
||||
bool wxTextBuffer::Create()
|
||||
{
|
||||
// buffer name must be either given in ctor or in Create(const wxString&)
|
||||
wxASSERT( !m_strBufferName.empty() );
|
||||
|
||||
// if the buffer already exists do nothing
|
||||
if ( Exists() ) return false;
|
||||
|
||||
if ( !OnOpen(m_strBufferName, WriteAccess) )
|
||||
return false;
|
||||
|
||||
OnClose();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxTextBuffer::Open(const wxString& strBufferName, const wxMBConv& conv)
|
||||
{
|
||||
m_strBufferName = strBufferName;
|
||||
|
||||
return Open(conv);
|
||||
}
|
||||
|
||||
bool wxTextBuffer::Open(const wxMBConv& conv)
|
||||
{
|
||||
// buffer name must be either given in ctor or in Open(const wxString&)
|
||||
wxASSERT( !m_strBufferName.empty() );
|
||||
|
||||
// open buffer in read-only mode
|
||||
if ( !OnOpen(m_strBufferName, ReadAccess) )
|
||||
return false;
|
||||
|
||||
// read buffer into memory
|
||||
m_isOpened = OnRead(conv);
|
||||
|
||||
OnClose();
|
||||
|
||||
return m_isOpened;
|
||||
}
|
||||
|
||||
// analyse some lines of the buffer trying to guess it's type.
|
||||
// if it fails, it assumes the native type for our platform.
|
||||
wxTextFileType wxTextBuffer::GuessType() const
|
||||
{
|
||||
wxASSERT( IsOpened() );
|
||||
|
||||
// scan the buffer lines
|
||||
size_t nUnix = 0, // number of '\n's alone
|
||||
nDos = 0, // number of '\r\n'
|
||||
nMac = 0; // number of '\r's
|
||||
|
||||
// we take MAX_LINES_SCAN in the beginning, middle and the end of buffer
|
||||
#define MAX_LINES_SCAN (10)
|
||||
size_t nCount = m_aLines.GetCount() / 3,
|
||||
nScan = nCount > 3*MAX_LINES_SCAN ? MAX_LINES_SCAN : nCount / 3;
|
||||
|
||||
#define AnalyseLine(n) \
|
||||
switch ( m_aTypes[n] ) { \
|
||||
case wxTextFileType_Unix: nUnix++; break; \
|
||||
case wxTextFileType_Dos: nDos++; break; \
|
||||
case wxTextFileType_Mac: nMac++; break; \
|
||||
default: wxFAIL_MSG(wxT("unknown line terminator")); \
|
||||
}
|
||||
|
||||
size_t n;
|
||||
for ( n = 0; n < nScan; n++ ) // the beginning
|
||||
AnalyseLine(n);
|
||||
for ( n = (nCount - nScan)/2; n < (nCount + nScan)/2; n++ )
|
||||
AnalyseLine(n);
|
||||
for ( n = nCount - nScan; n < nCount; n++ )
|
||||
AnalyseLine(n);
|
||||
|
||||
#undef AnalyseLine
|
||||
|
||||
// interpret the results (FIXME far from being even 50% fool proof)
|
||||
if ( nScan > 0 && nDos + nUnix + nMac == 0 ) {
|
||||
// no newlines at all
|
||||
wxLogWarning(_("'%s' is probably a binary buffer."), m_strBufferName.c_str());
|
||||
}
|
||||
else {
|
||||
#define GREATER_OF(t1, t2) n##t1 == n##t2 ? typeDefault \
|
||||
: n##t1 > n##t2 \
|
||||
? wxTextFileType_##t1 \
|
||||
: wxTextFileType_##t2
|
||||
|
||||
if ( nDos > nUnix )
|
||||
return GREATER_OF(Dos, Mac);
|
||||
else if ( nDos < nUnix )
|
||||
return GREATER_OF(Unix, Mac);
|
||||
else {
|
||||
// nDos == nUnix
|
||||
return nMac > nDos ? wxTextFileType_Mac : typeDefault;
|
||||
}
|
||||
|
||||
#undef GREATER_OF
|
||||
}
|
||||
|
||||
return typeDefault;
|
||||
}
|
||||
|
||||
|
||||
bool wxTextBuffer::Close()
|
||||
{
|
||||
Clear();
|
||||
m_isOpened = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxTextBuffer::Write(wxTextFileType typeNew, const wxMBConv& conv)
|
||||
{
|
||||
return OnWrite(typeNew, conv);
|
||||
}
|
||||
|
||||
#endif // wxUSE_TEXTBUFFER
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user