]> git.saurik.com Git - wxWidgets.git/blame - src/common/datstrm.cpp
Don't define wxArrayPGProperty as std::vector in STL build.
[wxWidgets.git] / src / common / datstrm.cpp
CommitLineData
cf447356 1/////////////////////////////////////////////////////////////////////////////
40319aa0 2// Name: src/common/datstrm.cpp
cf447356
GL
3// Purpose: Data stream classes
4// Author: Guilhem Lavaux
53663be8 5// Modified by: Mickael Gilabert
cf447356
GL
6// Created: 28/06/98
7// RCS-ID: $Id$
13111b2a 8// Copyright: (c) Guilhem Lavaux
68379eaf 9// Licence: wxWindows licence
cf447356
GL
10/////////////////////////////////////////////////////////////////////////////
11
cf447356
GL
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
ce4169a4 16 #pragma hdrstop
cf447356
GL
17#endif
18
ce4169a4
RR
19#if wxUSE_STREAMS
20
cf447356 21#include "wx/datstrm.h"
18680f86
WS
22
23#ifndef WX_PRECOMP
24 #include "wx/math.h"
25#endif //WX_PRECOMP
3cacae09 26
f4ada568
GL
27// ---------------------------------------------------------------------------
28// wxDataInputStream
29// ---------------------------------------------------------------------------
30
a99acbb0 31#if wxUSE_UNICODE
830f8f11 32wxDataInputStream::wxDataInputStream(wxInputStream& s, const wxMBConv& conv)
d36c9347 33 : m_input(&s), m_be_order(false), m_conv(conv.Clone())
a99acbb0 34#else
3d4c6a21 35wxDataInputStream::wxDataInputStream(wxInputStream& s)
68379eaf 36 : m_input(&s), m_be_order(false)
a99acbb0 37#endif
cf447356 38{
cf447356
GL
39}
40
d36c9347
VZ
41wxDataInputStream::~wxDataInputStream()
42{
43#if wxUSE_UNICODE
44 delete m_conv;
45#endif // wxUSE_UNICODE
46}
47
10c2f98a
RR
48#if wxUSE_UNICODE
49void wxDataInputStream::SetConv( const wxMBConv &conv )
50{
51 delete m_conv;
52 m_conv = conv.Clone();
53}
54#endif
55
216a72f3 56#if wxHAS_INT64
41b0a113
RL
57wxUint64 wxDataInputStream::Read64()
58{
216a72f3
VZ
59 wxUint64 tmp;
60 Read64(&tmp, 1);
61 return tmp;
41b0a113 62}
216a72f3 63#endif // wxHAS_INT64
41b0a113 64
7b8bd818 65wxUint32 wxDataInputStream::Read32()
cf447356 66{
5a96d2f4 67 wxUint32 i32;
cf447356 68
5a96d2f4 69 m_input->Read(&i32, 4);
cf447356 70
5a96d2f4
GL
71 if (m_be_order)
72 return wxUINT32_SWAP_ON_LE(i32);
73 else
74 return wxUINT32_SWAP_ON_BE(i32);
cf447356
GL
75}
76
7b8bd818 77wxUint16 wxDataInputStream::Read16()
cf447356 78{
5a96d2f4 79 wxUint16 i16;
cf447356 80
5a96d2f4 81 m_input->Read(&i16, 2);
cf447356 82
5a96d2f4
GL
83 if (m_be_order)
84 return wxUINT16_SWAP_ON_LE(i16);
85 else
86 return wxUINT16_SWAP_ON_BE(i16);
cf447356
GL
87}
88
7b8bd818 89wxUint8 wxDataInputStream::Read8()
cf447356 90{
7b8bd818 91 wxUint8 buf;
cf447356 92
5a96d2f4 93 m_input->Read(&buf, 1);
7b8bd818 94 return (wxUint8)buf;
cf447356
GL
95}
96
3d4c6a21 97double wxDataInputStream::ReadDouble()
cf447356 98{
47d67540 99#if wxUSE_APPLE_IEEE
cf447356
GL
100 char buf[10];
101
fae05df5 102 m_input->Read(buf, 10);
225dfbc5 103 return wxConvertFromIeeeExtended((const wxInt8 *)buf);
cf447356
GL
104#else
105 return 0.0;
106#endif
107}
108
3d4c6a21 109wxString wxDataInputStream::ReadString()
eafc087e 110{
0094bc4c 111 wxString ret;
eafc087e 112
0094bc4c
VZ
113 const size_t len = Read32();
114 if ( len > 0 )
115 {
2ae47e3f 116#if wxUSE_UNICODE
0094bc4c
VZ
117 wxCharBuffer tmp(len + 1);
118 if ( tmp )
119 {
120 m_input->Read(tmp.data(), len);
121 tmp.data()[len] = '\0';
122 ret = m_conv->cMB2WX(tmp.data());
123 }
2ae47e3f 124#else
0094bc4c
VZ
125 wxStringBuffer buf(ret, len);
126 if ( buf )
127 m_input->Read(buf, len);
2ae47e3f 128#endif
0094bc4c
VZ
129 }
130
2b5f62a0 131 return ret;
eafc087e 132}
13111b2a 133
216a72f3
VZ
134#if wxUSE_LONGLONG
135
136template <class T>
137static
138void DoReadLL(T *buffer, size_t size, wxInputStream *input, bool be_order)
53663be8 139{
216a72f3
VZ
140 typedef T DataType;
141 unsigned char *pchBuffer = new unsigned char[size * 8];
142 // TODO: Check for overflow when size is of type uint and is > than 512m
143 input->Read(pchBuffer, size * 8);
144 size_t idx_base = 0;
145 if ( be_order )
146 {
147 for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex )
148 {
149 buffer[uiIndex] = 0l;
150 for ( unsigned ui = 0; ui != 8; ++ui )
151 {
152 buffer[uiIndex] = buffer[uiIndex] * 256l +
153 DataType((unsigned long) pchBuffer[idx_base + ui]);
154 }
155
156 idx_base += 8;
157 }
158 }
159 else // little endian
160 {
161 for ( size_t uiIndex=0; uiIndex!=size; ++uiIndex )
162 {
163 buffer[uiIndex] = 0l;
164 for ( unsigned ui=0; ui!=8; ++ui )
165 buffer[uiIndex] = buffer[uiIndex] * 256l +
166 DataType((unsigned long) pchBuffer[idx_base + 7 - ui]);
167 idx_base += 8;
168 }
169 }
170 delete[] pchBuffer;
171}
53663be8 172
216a72f3
VZ
173template <class T>
174static void DoWriteLL(const T *buffer, size_t size, wxOutputStream *output, bool be_order)
175{
176 typedef T DataType;
177 unsigned char *pchBuffer = new unsigned char[size * 8];
178 size_t idx_base = 0;
179 if ( be_order )
180 {
181 for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex )
182 {
183 DataType i64 = buffer[uiIndex];
184 for ( unsigned ui = 0; ui != 8; ++ui )
185 {
186 pchBuffer[idx_base + 7 - ui] =
187 (unsigned char) (i64.GetLo() & 255l);
188 i64 >>= 8l;
189 }
190
191 idx_base += 8;
192 }
193 }
194 else // little endian
195 {
196 for ( size_t uiIndex=0; uiIndex != size; ++uiIndex )
197 {
198 DataType i64 = buffer[uiIndex];
199 for (unsigned ui=0; ui!=8; ++ui)
200 {
201 pchBuffer[idx_base + ui] =
202 (unsigned char) (i64.GetLo() & 255l);
203 i64 >>= 8l;
204 }
205
206 idx_base += 8;
207 }
208 }
209
210 // TODO: Check for overflow when size is of type uint and is > than 512m
211 output->Write(pchBuffer, size * 8);
212 delete[] pchBuffer;
213}
214
215#endif // wxUSE_LONGLONG
216
217#ifdef wxLongLong_t
218
219template <class T>
220static
221void DoReadI64(T *buffer, size_t size, wxInputStream *input, bool be_order)
222{
223 typedef T DataType;
224 unsigned char *pchBuffer = (unsigned char*) buffer;
225 // TODO: Check for overflow when size is of type uint and is > than 512m
226 input->Read(pchBuffer, size * 8);
227 if ( be_order )
228 {
229 for ( wxUint32 i = 0; i < size; i++ )
230 {
231 DataType v = wxUINT64_SWAP_ON_LE(*buffer);
232 *(buffer++) = v;
233 }
234 }
235 else // little endian
236 {
237 for ( wxUint32 i=0; i<size; i++ )
238 {
239 DataType v = wxUINT64_SWAP_ON_BE(*buffer);
240 *(buffer++) = v;
241 }
242 }
243}
244
245template <class T>
246static
247void DoWriteI64(const T *buffer, size_t size, wxOutputStream *output, bool be_order)
248{
249 typedef T DataType;
250 if ( be_order )
53663be8 251 {
216a72f3 252 for ( size_t i = 0; i < size; i++ )
53663be8 253 {
216a72f3
VZ
254 DataType i64 = wxUINT64_SWAP_ON_LE(*buffer);
255 buffer++;
256 output->Write(&i64, 8);
53663be8
VZ
257 }
258 }
216a72f3 259 else // little endian
53663be8 260 {
216a72f3 261 for ( size_t i=0; i < size; i++ )
53663be8 262 {
216a72f3
VZ
263 DataType i64 = wxUINT64_SWAP_ON_BE(*buffer);
264 buffer++;
265 output->Write(&i64, 8);
53663be8
VZ
266 }
267 }
268}
269
216a72f3
VZ
270#endif // wxLongLong_t
271
272
273#if wxHAS_INT64
274void wxDataInputStream::Read64(wxUint64 *buffer, size_t size)
275{
276#ifndef wxLongLong_t
277 DoReadLL(buffer, size, m_input, m_be_order);
278#else
279 DoReadI64(buffer, size, m_input, m_be_order);
280#endif
281}
282
283void wxDataInputStream::Read64(wxInt64 *buffer, size_t size)
284{
285#ifndef wxLongLong_t
286 DoReadLL(buffer, size, m_input, m_be_order);
287#else
288 DoReadI64(buffer, size, m_input, m_be_order);
289#endif
290}
291#endif // wxHAS_INT64
292
293#if defined(wxLongLong_t) && wxUSE_LONGLONG
294void wxDataInputStream::Read64(wxULongLong *buffer, size_t size)
295{
296 DoReadLL(buffer, size, m_input, m_be_order);
297}
298
299void wxDataInputStream::Read64(wxLongLong *buffer, size_t size)
300{
301 DoReadLL(buffer, size, m_input, m_be_order);
302}
303#endif // wxLongLong_t
304
305#if wxUSE_LONGLONG
306void wxDataInputStream::ReadLL(wxULongLong *buffer, size_t size)
307{
308 DoReadLL(buffer, size, m_input, m_be_order);
309}
310
311void wxDataInputStream::ReadLL(wxLongLong *buffer, size_t size)
312{
313 DoReadLL(buffer, size, m_input, m_be_order);
314}
315
316wxLongLong wxDataInputStream::ReadLL(void)
317{
318 wxLongLong ll;
40319aa0 319 DoReadLL(&ll, (size_t)1, m_input, m_be_order);
216a72f3
VZ
320 return ll;
321}
322#endif // wxUSE_LONGLONG
323
53663be8
VZ
324void wxDataInputStream::Read32(wxUint32 *buffer, size_t size)
325{
7448de8d 326 m_input->Read(buffer, size * 4);
53663be8 327
7448de8d 328 if (m_be_order)
53663be8 329 {
7448de8d
WS
330 for (wxUint32 i=0; i<size; i++)
331 {
332 wxUint32 v = wxUINT32_SWAP_ON_LE(*buffer);
333 *(buffer++) = v;
334 }
53663be8 335 }
7448de8d 336 else
53663be8 337 {
7448de8d
WS
338 for (wxUint32 i=0; i<size; i++)
339 {
340 wxUint32 v = wxUINT32_SWAP_ON_BE(*buffer);
341 *(buffer++) = v;
342 }
53663be8 343 }
53663be8
VZ
344}
345
346void wxDataInputStream::Read16(wxUint16 *buffer, size_t size)
347{
348 m_input->Read(buffer, size * 2);
349
350 if (m_be_order)
351 {
352 for (wxUint32 i=0; i<size; i++)
353 {
354 wxUint16 v = wxUINT16_SWAP_ON_LE(*buffer);
355 *(buffer++) = v;
356 }
357 }
358 else
359 {
360 for (wxUint32 i=0; i<size; i++)
361 {
362 wxUint16 v = wxUINT16_SWAP_ON_BE(*buffer);
363 *(buffer++) = v;
364 }
365 }
366}
367
368void wxDataInputStream::Read8(wxUint8 *buffer, size_t size)
369{
370 m_input->Read(buffer, size);
371}
372
373void wxDataInputStream::ReadDouble(double *buffer, size_t size)
374{
375 for (wxUint32 i=0; i<size; i++)
376 {
377 *(buffer++) = ReadDouble();
378 }
379}
380
fae05df5
GL
381wxDataInputStream& wxDataInputStream::operator>>(wxString& s)
382{
383 s = ReadString();
384 return *this;
385}
386
387wxDataInputStream& wxDataInputStream::operator>>(wxInt8& c)
388{
389 c = (wxInt8)Read8();
390 return *this;
391}
392
393wxDataInputStream& wxDataInputStream::operator>>(wxInt16& i)
394{
395 i = (wxInt16)Read16();
396 return *this;
397}
398
399wxDataInputStream& wxDataInputStream::operator>>(wxInt32& i)
400{
401 i = (wxInt32)Read32();
402 return *this;
403}
404
405wxDataInputStream& wxDataInputStream::operator>>(wxUint8& c)
406{
407 c = Read8();
408 return *this;
409}
410
411wxDataInputStream& wxDataInputStream::operator>>(wxUint16& i)
412{
413 i = Read16();
414 return *this;
415}
416
417wxDataInputStream& wxDataInputStream::operator>>(wxUint32& i)
418{
419 i = Read32();
420 return *this;
421}
422
216a72f3 423#if wxHAS_INT64
41b0a113
RL
424wxDataInputStream& wxDataInputStream::operator>>(wxUint64& i)
425{
426 i = Read64();
427 return *this;
428}
429
216a72f3
VZ
430wxDataInputStream& wxDataInputStream::operator>>(wxInt64& i)
431{
432 i = Read64();
433 return *this;
434}
435#endif // wxHAS_INT64
436
437#if defined(wxLongLong_t) && wxUSE_LONGLONG
438wxDataInputStream& wxDataInputStream::operator>>(wxULongLong& i)
439{
440 i = ReadLL();
441 return *this;
442}
443
444wxDataInputStream& wxDataInputStream::operator>>(wxLongLong& i)
445{
446 i = ReadLL();
447 return *this;
448}
449#endif // wxLongLong_t
450
fae05df5
GL
451wxDataInputStream& wxDataInputStream::operator>>(double& i)
452{
453 i = ReadDouble();
454 return *this;
455}
456
457wxDataInputStream& wxDataInputStream::operator>>(float& f)
458{
459 f = (float)ReadDouble();
460 return *this;
461}
eafc087e 462
f4ada568
GL
463// ---------------------------------------------------------------------------
464// wxDataOutputStream
465// ---------------------------------------------------------------------------
466
a99acbb0 467#if wxUSE_UNICODE
830f8f11 468wxDataOutputStream::wxDataOutputStream(wxOutputStream& s, const wxMBConv& conv)
d36c9347 469 : m_output(&s), m_be_order(false), m_conv(conv.Clone())
a99acbb0 470#else
3d4c6a21 471wxDataOutputStream::wxDataOutputStream(wxOutputStream& s)
68379eaf 472 : m_output(&s), m_be_order(false)
a99acbb0 473#endif
3d4c6a21
GL
474{
475}
476
d36c9347
VZ
477wxDataOutputStream::~wxDataOutputStream()
478{
479#if wxUSE_UNICODE
480 delete m_conv;
481#endif // wxUSE_UNICODE
482}
483
10c2f98a
RR
484#if wxUSE_UNICODE
485void wxDataOutputStream::SetConv( const wxMBConv &conv )
486{
487 delete m_conv;
488 m_conv = conv.Clone();
489}
490#endif
491
216a72f3 492#if wxHAS_INT64
41b0a113
RL
493void wxDataOutputStream::Write64(wxUint64 i)
494{
216a72f3
VZ
495 Write64(&i, 1);
496}
41b0a113 497
216a72f3
VZ
498void wxDataOutputStream::Write64(wxInt64 i)
499{
500 Write64(&i, 1);
41b0a113 501}
216a72f3 502#endif // wxHAS_INT64
41b0a113 503
7b8bd818 504void wxDataOutputStream::Write32(wxUint32 i)
cf447356 505{
5a96d2f4 506 wxUint32 i32;
cf447356 507
5a96d2f4
GL
508 if (m_be_order)
509 i32 = wxUINT32_SWAP_ON_LE(i);
510 else
511 i32 = wxUINT32_SWAP_ON_BE(i);
512 m_output->Write(&i32, 4);
cf447356
GL
513}
514
7b8bd818 515void wxDataOutputStream::Write16(wxUint16 i)
cf447356 516{
5a96d2f4 517 wxUint16 i16;
cf447356 518
5a96d2f4
GL
519 if (m_be_order)
520 i16 = wxUINT16_SWAP_ON_LE(i);
521 else
522 i16 = wxUINT16_SWAP_ON_BE(i);
523
524 m_output->Write(&i16, 2);
cf447356
GL
525}
526
7b8bd818 527void wxDataOutputStream::Write8(wxUint8 i)
cf447356 528{
fae05df5 529 m_output->Write(&i, 1);
cf447356
GL
530}
531
3d4c6a21 532void wxDataOutputStream::WriteString(const wxString& string)
eafc087e 533{
a99acbb0 534#if wxUSE_UNICODE
d36c9347 535 const wxWX2MBbuf buf = string.mb_str(*m_conv);
a99acbb0 536#else
c980c992 537 const wxWX2MBbuf buf = string.mb_str();
a99acbb0
VS
538#endif
539 size_t len = strlen(buf);
540 Write32(len);
541 if (len > 0)
542 m_output->Write(buf, len);
cf447356
GL
543}
544
3d4c6a21 545void wxDataOutputStream::WriteDouble(double d)
cf447356 546{
cf447356
GL
547 char buf[10];
548
47d67540 549#if wxUSE_APPLE_IEEE
225dfbc5 550 wxConvertToIeeeExtended(d, (wxInt8 *)buf);
0e338ff9 551#else
36e5a9a7 552 wxUnusedVar(d);
c5ceb215 553#if !defined(__VMS__) && !defined(__GNUG__)
338dd992
JJ
554# pragma warning "wxDataOutputStream::WriteDouble() not using IeeeExtended - will not work!"
555#endif
556 buf[0] = '\0';
0e338ff9 557#endif
fae05df5
GL
558 m_output->Write(buf, 10);
559}
560
216a72f3 561#if wxHAS_INT64
53663be8
VZ
562void wxDataOutputStream::Write64(const wxUint64 *buffer, size_t size)
563{
216a72f3
VZ
564#ifndef wxLongLong_t
565 DoWriteLL(buffer, size, m_output, m_be_order);
566#else
567 DoWriteI64(buffer, size, m_output, m_be_order);
568#endif
569}
570
571void wxDataOutputStream::Write64(const wxInt64 *buffer, size_t size)
572{
573#ifndef wxLongLong_t
574 DoWriteLL(buffer, size, m_output, m_be_order);
575#else
576 DoWriteI64(buffer, size, m_output, m_be_order);
577#endif
53663be8 578}
216a72f3
VZ
579#endif // wxHAS_INT64
580
581#if defined(wxLongLong_t) && wxUSE_LONGLONG
582void wxDataOutputStream::Write64(const wxULongLong *buffer, size_t size)
583{
584 DoWriteLL(buffer, size, m_output, m_be_order);
585}
586
587void wxDataOutputStream::Write64(const wxLongLong *buffer, size_t size)
588{
589 DoWriteLL(buffer, size, m_output, m_be_order);
590}
591#endif // wxLongLong_t
592
593#if wxUSE_LONGLONG
594void wxDataOutputStream::WriteLL(const wxULongLong *buffer, size_t size)
595{
596 DoWriteLL(buffer, size, m_output, m_be_order);
597}
598
599void wxDataOutputStream::WriteLL(const wxLongLong *buffer, size_t size)
600{
601 DoWriteLL(buffer, size, m_output, m_be_order);
602}
603
604void wxDataOutputStream::WriteLL(const wxLongLong &ll)
605{
606 WriteLL(&ll, 1);
607}
608
609void wxDataOutputStream::WriteLL(const wxULongLong &ll)
610{
611 WriteLL(&ll, 1);
612}
613#endif // wxUSE_LONGLONG
53663be8
VZ
614
615void wxDataOutputStream::Write32(const wxUint32 *buffer, size_t size)
616{
617 if (m_be_order)
618 {
619 for (wxUint32 i=0; i<size ;i++)
620 {
621 wxUint32 i32 = wxUINT32_SWAP_ON_LE(*buffer);
622 buffer++;
623 m_output->Write(&i32, 4);
624 }
625 }
626 else
627 {
628 for (wxUint32 i=0; i<size ;i++)
629 {
630 wxUint32 i32 = wxUINT32_SWAP_ON_BE(*buffer);
631 buffer++;
632 m_output->Write(&i32, 4);
633 }
634 }
635}
636
637void wxDataOutputStream::Write16(const wxUint16 *buffer, size_t size)
638{
639 if (m_be_order)
640 {
641 for (wxUint32 i=0; i<size ;i++)
642 {
643 wxUint16 i16 = wxUINT16_SWAP_ON_LE(*buffer);
644 buffer++;
645 m_output->Write(&i16, 2);
646 }
647 }
648 else
649 {
650 for (wxUint32 i=0; i<size ;i++)
651 {
652 wxUint16 i16 = wxUINT16_SWAP_ON_BE(*buffer);
653 buffer++;
654 m_output->Write(&i16, 2);
655 }
656 }
657}
658
659void wxDataOutputStream::Write8(const wxUint8 *buffer, size_t size)
660{
661 m_output->Write(buffer, size);
662}
663
664void wxDataOutputStream::WriteDouble(const double *buffer, size_t size)
665{
666 for (wxUint32 i=0; i<size; i++)
667 {
668 WriteDouble(*(buffer++));
669 }
670}
671
38caaa61 672wxDataOutputStream& wxDataOutputStream::operator<<(const wxString& string)
fae05df5
GL
673{
674 WriteString(string);
675 return *this;
676}
677
678wxDataOutputStream& wxDataOutputStream::operator<<(wxInt8 c)
679{
680 Write8((wxUint8)c);
681 return *this;
682}
683
684wxDataOutputStream& wxDataOutputStream::operator<<(wxInt16 i)
685{
686 Write16((wxUint16)i);
687 return *this;
688}
689
690wxDataOutputStream& wxDataOutputStream::operator<<(wxInt32 i)
691{
692 Write32((wxUint32)i);
693 return *this;
694}
695
696wxDataOutputStream& wxDataOutputStream::operator<<(wxUint8 c)
697{
698 Write8(c);
699 return *this;
700}
701
702wxDataOutputStream& wxDataOutputStream::operator<<(wxUint16 i)
703{
704 Write16(i);
705 return *this;
706}
707
708wxDataOutputStream& wxDataOutputStream::operator<<(wxUint32 i)
709{
710 Write32(i);
711 return *this;
712}
713
216a72f3 714#if wxHAS_INT64
41b0a113
RL
715wxDataOutputStream& wxDataOutputStream::operator<<(wxUint64 i)
716{
717 Write64(i);
718 return *this;
719}
720
216a72f3
VZ
721wxDataOutputStream& wxDataOutputStream::operator<<(wxInt64 i)
722{
723 Write64(i);
724 return *this;
725}
726#endif // wxHAS_INT64
727
728#if defined(wxLongLong_t) && wxUSE_LONGLONG
729wxDataOutputStream& wxDataOutputStream::operator<<(const wxULongLong &i)
730{
731 WriteLL(i);
732 return *this;
733}
734
735wxDataOutputStream& wxDataOutputStream::operator<<(const wxLongLong &i)
736{
737 WriteLL(i);
738 return *this;
739}
740#endif // wxLongLong_t
741
fae05df5
GL
742wxDataOutputStream& wxDataOutputStream::operator<<(double f)
743{
744 WriteDouble(f);
745 return *this;
746}
747
748wxDataOutputStream& wxDataOutputStream::operator<<(float f)
749{
750 WriteDouble((double)f);
751 return *this;
cf447356 752}
ce4169a4
RR
753
754#endif
755 // wxUSE_STREAMS