Merge pull request #1 from MaddTheSane/upstream-pcsx2

Implement PCSX2.

Thanks to @duckey77 for making sure it runs.
This commit is contained in:
C.W. Betts
2022-02-25 14:38:46 -07:00
committed by GitHub
694 changed files with 256698 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
.DS_Store
*.xcuserdata/
xcuserdata/
+3
View File
@@ -0,0 +1,3 @@
[submodule "pcsx2"]
path = pcsx2
url = https://github.com/tellowkrinkle/pcsx2.git
+855
View File
@@ -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;
}
}
}
+6
View File
@@ -0,0 +1,6 @@
#include "SPU2/Global.h"
namespace Host
{
void WriteToSoundBuffer(s16 Left, s16 Right);
}
+62
View File
@@ -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 */
+7
View File
@@ -0,0 +1,7 @@
# PCSX2Exports.exp
# PCSX2
#
# Created by C.W. Betts on 2/2/22.
#
.objc_class_name_PCSX2GameCore
+37
View File
@@ -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
+676
View File
@@ -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()
+147
View File
@@ -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
+205
View File
@@ -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__
+398
View File
@@ -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__
+372
View File
@@ -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, &current_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();
}
+33
View File
@@ -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 */
+31
View File
@@ -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
+87
View File
@@ -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>
+183
View File
@@ -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
+542
View File
@@ -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
+37
View File
@@ -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
+39
View File
@@ -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
+94
View File
@@ -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 = &notifier;
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
+926
View File
@@ -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__ )
}
+237
View File
@@ -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
+77
View File
@@ -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
+600
View File
@@ -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;
}
}
+400
View File
@@ -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;
}
+499
View File
@@ -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
+849
View File
@@ -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
+756
View File
@@ -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
+401
View File
@@ -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);
}
+247
View File
@@ -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
+399
View File
@@ -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
+504
View File
@@ -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
+397
View File
@@ -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__
+193
View File
@@ -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 */
+143
View File
@@ -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);
+398
View File
@@ -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
+630
View File
@@ -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
+330
View 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
+715
View File
@@ -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
+32
View File
@@ -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
+39
View File
@@ -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
+868
View File
@@ -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
+334
View File
@@ -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();
}
}
+518
View File
@@ -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
+88
View File
@@ -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
+168
View File
@@ -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
+274
View File
@@ -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
+326
View File
@@ -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
+390
View File
@@ -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
+379
View File
@@ -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;
}
+138
View File
@@ -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
+567
View File
@@ -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
+127
View File
@@ -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;
}
}
+799
View File
@@ -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
+745
View File
@@ -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
+403
View File
@@ -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
+601
View File
@@ -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 &degrees, 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
+757
View File
@@ -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
+116
View File
@@ -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);
}
}
+246
View File
@@ -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;
}
+234
View File
@@ -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
+203
View File
@@ -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
+334
View File
@@ -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);
}
+409
View File
@@ -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;
}
+107
View File
@@ -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
+171
View File
@@ -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
+375
View File
@@ -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;
}
+71
View File
@@ -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
+194
View File
@@ -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
+715
View File
@@ -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
+267
View File
@@ -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
+127
View File
@@ -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
+223
View File
@@ -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
+176
View File
@@ -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;
}
+264
View File
@@ -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
+176
View File
@@ -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
+791
View File
@@ -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
+351
View File
@@ -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
+771
View File
@@ -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;
}
+108
View File
@@ -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
+270
View File
@@ -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