]> git.saurik.com Git - wxWidgets.git/blame - src/common/anidecod.cpp
Implement left indentation and tab stops support in wxTextCtrl, patch #1518114 -...
[wxWidgets.git] / src / common / anidecod.cpp
CommitLineData
72045d57
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/anidecod.cpp
3// Purpose: wxANIDecoder, ANI reader for wxImage and wxAnimation
4// Author: Francesco Montorsi
5// RCS-ID: $Id$
6// Copyright: (c) Francesco Montorsi
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
13#ifdef __BORLANDC__
14 #pragma hdrstop
15#endif
16
d18868bb 17#if wxUSE_STREAMS && wxUSE_ICO_CUR
72045d57 18
14c0d834
PC
19#include "wx/anidecod.h"
20
72045d57
VZ
21#ifndef WX_PRECOMP
22 #include "wx/palette.h"
23#endif
24
25#include <stdlib.h>
26#include <string.h>
72045d57
VZ
27
28// static
29wxCURHandler wxANIDecoder::sm_handler;
30
72045d57
VZ
31//---------------------------------------------------------------------------
32// wxANIFrameInfo
33//---------------------------------------------------------------------------
34
35class wxANIFrameInfo
36{
37public:
9d9e3858 38 wxANIFrameInfo(size_t delay = 0, int idx = -1)
72045d57
VZ
39 { m_delay=delay; m_imageIndex=idx; }
40
41 size_t m_delay;
42 int m_imageIndex;
43};
44
14c0d834
PC
45#include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
46WX_DEFINE_OBJARRAY(wxImageArray)
72045d57 47
14c0d834
PC
48#include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
49WX_DEFINE_OBJARRAY(wxANIFrameInfoArray)
72045d57
VZ
50
51
52//---------------------------------------------------------------------------
53// wxANIDecoder
54//---------------------------------------------------------------------------
55
56wxANIDecoder::wxANIDecoder()
57{
58}
59
60wxANIDecoder::~wxANIDecoder()
61{
62}
63
64bool wxANIDecoder::ConvertToImage(size_t frame, wxImage *image) const
65{
66 size_t idx = m_info[frame].m_imageIndex;
67 *image = m_images[idx]; // copy
9d9e3858 68 return image->IsOk();
72045d57
VZ
69}
70
71
72//---------------------------------------------------------------------------
73// Data accessors
74//---------------------------------------------------------------------------
75
76wxSize wxANIDecoder::GetFrameSize(size_t WXUNUSED(frame)) const
77{
78 // all frames are of the same size...
79 return m_szAnimation;
80}
81
82wxPoint wxANIDecoder::GetFramePosition(size_t WXUNUSED(frame)) const
83{
84 // all frames are of the same size...
85 return wxPoint(0,0);
86}
87
88wxAnimationDisposal wxANIDecoder::GetDisposalMethod(size_t WXUNUSED(frame)) const
89{
90 // this disposal is implicit for all frames inside an ANI file
91 return wxANIM_TOBACKGROUND;
92}
93
94long wxANIDecoder::GetDelay(size_t frame) const
95{
96 return m_info[frame].m_delay;
97}
98
99
100//---------------------------------------------------------------------------
101// ANI reading and decoding
102//---------------------------------------------------------------------------
103
104bool wxANIDecoder::CanRead(wxInputStream& stream) const
105{
106 wxInt32 FCC1, FCC2;
107 wxUint32 datalen ;
108
109 wxInt32 riff32;
110 memcpy( &riff32, "RIFF", 4 );
111 wxInt32 list32;
112 memcpy( &list32, "LIST", 4 );
113 wxInt32 ico32;
114 memcpy( &ico32, "icon", 4 );
115 wxInt32 anih32;
116 memcpy( &anih32, "anih", 4 );
117
118 stream.SeekI(0);
119 if ( !stream.Read(&FCC1, 4) )
120 return false;
121
122 if ( FCC1 != riff32 )
123 return false;
124
125 // we have a riff file:
126 while ( stream.IsOk() )
127 {
128 if ( FCC1 == anih32 )
129 return true; // found the ANIH chunk - this should be an ANI file
130
131 // we always have a data size:
132 stream.Read(&datalen, 4);
133 datalen = wxINT32_SWAP_ON_BE(datalen) ;
9d9e3858 134
72045d57
VZ
135 // data should be padded to make even number of bytes
136 if (datalen % 2 == 1) datalen ++ ;
137
138 // now either data or a FCC:
139 if ( (FCC1 == riff32) || (FCC1 == list32) )
140 {
141 stream.Read(&FCC2, 4);
142 }
143 else
144 {
145 stream.SeekI(stream.TellI() + datalen);
146 }
147
148 // try to read next data chunk:
149 if ( !stream.Read(&FCC1, 4) )
150 {
151 // reading failed -- either EOF or IO error, bail out anyhow
152 return false;
153 }
154 }
155
156 return false;
157}
158
159// the "anih" RIFF chunk
9d9e3858 160struct wxANIHeader
72045d57
VZ
161{
162 wxInt32 cbSizeOf; // Num bytes in AniHeader (36 bytes)
163 wxInt32 cFrames; // Number of unique Icons in this cursor
164 wxInt32 cSteps; // Number of Blits before the animation cycles
165 wxInt32 cx; // width of the frames
166 wxInt32 cy; // height of the frames
167 wxInt32 cBitCount; // bit depth
168 wxInt32 cPlanes; // 1
169 wxInt32 JifRate; // Default Jiffies (1/60th of a second) if rate chunk not present.
170 wxInt32 flags; // Animation Flag (see AF_ constants)
ce7efe2d
VZ
171
172 // ANI files are always little endian so we need to swap bytes on big
173 // endian architectures
174#ifdef WORDS_BIGENDIAN
175 void AdjustEndianness()
176 {
177 // this works because all our fields are wxInt32 and they must be
178 // packed without holes between them (if they're not, they wouldn't map
179 // to the file header!)
180 wxInt32 * const start = (wxInt32 *)this;
181 wxInt32 * const end = start + sizeof(wxANIHeader)/sizeof(wxInt32);
182 for ( wxInt32 *p = start; p != end; p++ )
183 {
184 *p = wxINT32_SWAP_ALWAYS(*p);
185 }
186 }
187#else
188 void AdjustEndianness() { }
189#endif
72045d57
VZ
190};
191
192bool wxANIDecoder::Load( wxInputStream& stream )
193{
194 wxInt32 FCC1, FCC2;
195 wxUint32 datalen;
196 size_t globaldelay=0;
197
198 wxInt32 riff32;
199 memcpy( &riff32, "RIFF", 4 );
200 wxInt32 list32;
201 memcpy( &list32, "LIST", 4 );
202 wxInt32 ico32;
203 memcpy( &ico32, "icon", 4 );
204 wxInt32 anih32;
205 memcpy( &anih32, "anih", 4 );
206 wxInt32 rate32;
207 memcpy( &rate32, "rate", 4 );
208 wxInt32 seq32;
209 memcpy( &seq32, "seq ", 4 );
210
211 stream.SeekI(0);
212 stream.Read(&FCC1, 4);
213 if ( FCC1 != riff32 )
214 return false;
215
216 m_nFrames = 0;
217 m_szAnimation = wxDefaultSize;
218
219 m_images.Clear();
220 m_info.Clear();
221
222 // we have a riff file:
223 while ( stream.IsOk() )
224 {
225 // we always have a data size:
226 stream.Read(&datalen, 4);
227 datalen = wxINT32_SWAP_ON_BE(datalen);
228
229 //data should be padded to make even number of bytes
230 if (datalen % 2 == 1) datalen++;
231
232 // now either data or a FCC:
233 if ( (FCC1 == riff32) || (FCC1 == list32) )
234 {
235 stream.Read(&FCC2, 4);
236 }
237 else if ( FCC1 == anih32 )
238 {
239 if ( datalen != sizeof(wxANIHeader) )
240 return false;
241
242 if (m_nFrames > 0)
243 return false; // already parsed an ani header?
244
245 struct wxANIHeader header;
246 stream.Read(&header, sizeof(wxANIHeader));
ce7efe2d 247 header.AdjustEndianness();
72045d57
VZ
248
249 // we should have a global frame size
250 m_szAnimation = wxSize(header.cx, header.cy);
251
252 // save interesting info from the header
253 m_nFrames = header.cSteps; // NB: not cFrames!!
9d9e3858 254 if ( m_nFrames == 0 )
72045d57
VZ
255 return false;
256
ce7efe2d 257 globaldelay = header.JifRate * 1000 / 60;
72045d57
VZ
258
259 m_images.Alloc(header.cFrames);
260 m_info.Add(wxANIFrameInfo(), m_nFrames);
261 }
262 else if ( FCC1 == rate32 )
263 {
264 // did we already process the anih32 chunk?
265 if (m_nFrames == 0)
266 return false; // rate chunks should always be placed after anih chunk
9d9e3858 267
72045d57
VZ
268 wxASSERT(m_info.GetCount() == m_nFrames);
269 for (size_t i=0; i<m_nFrames; i++)
270 {
271 stream.Read(&FCC2, 4);
272 m_info[i].m_delay = wxINT32_SWAP_ON_BE(FCC2) * 1000 / 60;
273 }
274 }
275 else if ( FCC1 == seq32 )
276 {
277 // did we already process the anih32 chunk?
278 if (m_nFrames == 0)
279 return false; // seq chunks should always be placed after anih chunk
280
281 wxASSERT(m_info.GetCount() == m_nFrames);
282 for (size_t i=0; i<m_nFrames; i++)
283 {
284 stream.Read(&FCC2, 4);
285 m_info[i].m_imageIndex = wxINT32_SWAP_ON_BE(FCC2);
286 }
287 }
288 else if ( FCC1 == ico32 )
289 {
290 // use DoLoadFile() and not LoadFile()!
291 wxImage image;
292 if (!sm_handler.DoLoadFile(&image, stream, false /* verbose */, -1))
293 return false;
294
295 m_images.Add(image);
296 }
297 else
ce7efe2d 298 {
72045d57 299 stream.SeekI(stream.TellI() + datalen);
ce7efe2d 300 }
72045d57
VZ
301
302 // try to read next data chunk:
303 stream.Read(&FCC1, 4);
304 }
305
306 if (m_nFrames==0)
307 return false;
308
309 if (m_nFrames==m_images.GetCount())
310 {
311 // if no SEQ chunk is available, display the frames in the order
312 // they were loaded
313 for (size_t i=0; i<m_nFrames; i++)
314 if (m_info[i].m_imageIndex == -1)
315 m_info[i].m_imageIndex = i;
316 }
317
318 // if some frame has an invalid delay, use the global delay given in the
319 // ANI header
320 for (size_t i=0; i<m_nFrames; i++)
321 if (m_info[i].m_delay == 0)
322 m_info[i].m_delay = globaldelay;
323
324 // if the header did not contain a valid frame size, try to grab
325 // it from the size of the first frame (all frames are of the same size)
326 if (m_szAnimation.GetWidth() == 0 ||
327 m_szAnimation.GetHeight() == 0)
328 m_szAnimation = wxSize(m_images[0].GetWidth(), m_images[0].GetHeight());
329
14c0d834 330 return m_szAnimation != wxDefaultSize;
72045d57
VZ
331}
332
d18868bb 333#endif // wxUSE_STREAMS && wxUSE_ICO_CUR