2008-05-28 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / corlib / System.Resources / ResourceReader.cs
1 //
2 // System.Resources.ResourceReader.cs
3 //
4 // Authors: 
5 //      Duncan Mak <duncan@ximian.com>
6 //      Nick Drochak <ndrochak@gol.com>
7 //      Dick Porter <dick@ximian.com>
8 //      Marek Safar <marek.safar@seznam.cz>
9 //      Atsushi Enomoto  <atsushi@ximian.com>
10 //
11 // (C) 2001, 2002 Ximian Inc, http://www.ximian.com
12 // Copyright (C) 2004-2005,2007 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System.Collections;
35 using System.Resources;
36 using System.IO;
37 using System.Text;
38 using System.Runtime.InteropServices;
39 using System.Runtime.Serialization;
40 using System.Runtime.Serialization.Formatters.Binary;
41 using System.Security.Permissions;
42 #if NET_2_0
43 using System.Collections.Generic;
44 #endif
45
46 namespace System.Resources
47 {
48         internal enum PredefinedResourceType
49         {
50                 Null            = 0,
51                 String          = 1,
52                 Bool            = 2,
53                 Char            = 3,
54                 Byte            = 4,
55                 SByte           = 5,
56                 Int16           = 6,
57                 UInt16          = 7,
58                 Int32           = 8,
59                 UInt32          = 9,
60                 Int64           = 10,
61                 UInt64          = 11,
62                 Single          = 12,
63                 Double          = 13,
64                 Decimal         = 14,
65                 DateTime        = 15,
66                 TimeSpan        = 16,
67                 ByteArray       = 32,
68                 Stream          = 33,
69                 FistCustom      = 64
70         }
71
72 #if NET_2_0
73         [System.Runtime.InteropServices.ComVisible (true)]
74 #endif
75         public sealed class ResourceReader : IResourceReader, IEnumerable, IDisposable
76         {
77                 struct ResourceInfo
78                 {
79                         public readonly long ValuePosition;
80                         public readonly string ResourceName;
81                         public readonly int TypeIndex;
82                         
83                         public ResourceInfo (string resourceName, long valuePosition, int type_index)
84                         {
85                                 ValuePosition = valuePosition;
86                                 ResourceName = resourceName;
87                                 TypeIndex = type_index;
88                         }
89                 }
90
91                 struct ResourceCacheItem
92                 {
93                         public readonly string ResourceName;
94                         public readonly object ResourceValue;
95
96                         public ResourceCacheItem (string name, object value)
97                         {
98                                 ResourceName = name;
99                                 ResourceValue = value;
100                         }
101                 }
102                 
103                 BinaryReader reader;
104                 object readerLock = new object ();
105                 IFormatter formatter;
106                 internal int resourceCount = 0;
107                 int typeCount = 0;
108                 string[] typeNames;
109                 int[] hashes;
110                 ResourceInfo[] infos;
111                 int dataSectionOffset;
112                 long nameSectionOffset;
113                 int resource_ver;
114                 
115                 // Constructors
116                 [SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)]
117                 public ResourceReader (Stream stream)
118                 {
119                         if (stream == null)
120                                 throw new ArgumentNullException ("stream");
121                         
122                         if (!stream.CanRead)
123                                 throw new ArgumentException ("Stream was not readable.");
124
125                         reader = new BinaryReader(stream, Encoding.UTF8);
126                         formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File|StreamingContextStates.Persistence));
127                         
128                         ReadHeaders();
129                 }
130                 
131                 public ResourceReader (string fileName)
132                 {
133                         reader = new BinaryReader (new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read));
134                         formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File|StreamingContextStates.Persistence));
135
136                         ReadHeaders();
137                 }
138                 
139                 /* Read the ResourceManager header and the
140                  * ResourceReader header.
141                  */
142                 private void ReadHeaders()
143                 {
144                         try {
145                                 int manager_magic = reader.ReadInt32();
146
147                                 if(manager_magic != ResourceManager.MagicNumber) 
148                                         throw new ArgumentException(String.Format ("Stream is not a valid .resources file, magic=0x{0:x}", manager_magic));
149
150                                 int manager_ver = reader.ReadInt32();
151                                 int manager_len = reader.ReadInt32();
152                                 
153                                 /* We know how long the header is, even if
154                                  * the version number is too new
155                                  */
156                                 if(manager_ver > ResourceManager.HeaderVersionNumber) {
157                                         reader.BaseStream.Seek(manager_len, SeekOrigin.Current);
158                                 } else {
159                                         string reader_class=reader.ReadString();
160                                         if(!reader_class.StartsWith("System.Resources.ResourceReader")) {
161                                                 throw new NotSupportedException("This .resources file requires reader class " + reader_class);
162                                         }
163                                         
164                                         string set_class=reader.ReadString();
165                                         if(!set_class.StartsWith(typeof(ResourceSet).FullName) && !set_class.StartsWith("System.Resources.RuntimeResourceSet")) {
166                                                 throw new NotSupportedException("This .resources file requires set class " + set_class);
167                                         }
168                                 }
169
170                                 /* Now read the ResourceReader header */
171                                 resource_ver = reader.ReadInt32();
172
173                                 if(resource_ver != 1
174 #if NET_2_0
175                                         && resource_ver != 2
176 #endif
177                                         ) {
178                                         throw new NotSupportedException("This .resources file requires unsupported set class version: " + resource_ver.ToString());
179                                 }
180
181                                 resourceCount = reader.ReadInt32();
182                                 typeCount = reader.ReadInt32();
183                                 
184                                 typeNames=new string[typeCount];
185
186                                 for(int i=0; i<typeCount; i++) {
187                                         typeNames[i]=reader.ReadString();
188                                 }
189
190                                 /* There are between 0 and 7 bytes of
191                                  * padding here, consisting of the
192                                  * letters PAD.  The next item (Hash
193                                  * values for each resource name) need
194                                  * to be aligned on an 8-byte
195                                  * boundary.
196                                  */
197
198                                 int pad_align=(int)(reader.BaseStream.Position & 7);
199                                 int pad_chars=0;
200
201                                 if(pad_align!=0) {
202                                         pad_chars=8-pad_align;
203                                 }
204
205                                 for(int i=0; i<pad_chars; i++) {
206                                         byte pad_byte=reader.ReadByte();
207                                         if(pad_byte!="PAD"[i%3]) {
208                                                 throw new ArgumentException("Malformed .resources file (padding values incorrect)");
209                                         }
210                                 }
211                                 /* Read in the hash values for each
212                                  * resource name.  These can be used
213                                  * by ResourceSet (calling internal
214                                  * methods) to do a fast compare on
215                                  * resource names without doing
216                                  * expensive string compares (but we
217                                  * dont do that yet, so far we only
218                                  * implement the Enumerator interface)
219                                  */
220                                 hashes=new int[resourceCount];
221                                 for(int i=0; i<resourceCount; i++) {
222                                         hashes[i]=reader.ReadInt32();
223                                 }
224                                 
225                                 /* Read in the virtual offsets for
226                                  * each resource name
227                                  */
228                                 long[] positions = new long [resourceCount];
229                                 for(int i = 0; i < resourceCount; i++)
230                                         positions [i] = reader.ReadInt32();
231                                 
232                                 dataSectionOffset = reader.ReadInt32();
233                                 nameSectionOffset = reader.BaseStream.Position;
234
235                                 long origPosition = reader.BaseStream.Position;
236                                 infos = new ResourceInfo [resourceCount];
237                                 for (int i = 0; i < resourceCount; i++)
238                                         infos [i] = CreateResourceInfo (positions [i]);
239                                 reader.BaseStream.Seek (origPosition, SeekOrigin.Begin);
240                                 
241                                 positions = null;
242                         } catch(EndOfStreamException e) {
243                                 throw new ArgumentException("Stream is not a valid .resources file!  It was possibly truncated.", e);
244                         }
245                 }
246
247                 ResourceInfo CreateResourceInfo (long position)
248                 {
249                         long pos = position + nameSectionOffset;
250
251                         reader.BaseStream.Seek (pos, SeekOrigin.Begin);
252
253                         // Resource name
254                         int len = Read7BitEncodedInt ();
255                         byte[] str = new byte [len];
256                         
257                         reader.Read (str, 0, len);
258                         string resourceName = Encoding.Unicode.GetString (str);
259
260                         long data_offset = reader.ReadInt32 () + dataSectionOffset;
261                         reader.BaseStream.Seek (data_offset, SeekOrigin.Begin);
262                         int type_index = Read7BitEncodedInt ();
263                         
264                         return new ResourceInfo (resourceName, reader.BaseStream.Position, type_index);
265                 }
266                 
267                 /* Cut and pasted from BinaryReader, because it's
268                  * 'protected' there
269                  */
270                 private int Read7BitEncodedInt() {
271                         int ret = 0;
272                         int shift = 0;
273                         byte b;
274
275                         do {
276                                 b = reader.ReadByte();
277                                 
278                                 ret = ret | ((b & 0x7f) << shift);
279                                 shift += 7;
280                         } while ((b & 0x80) == 0x80);
281
282                         return ret;
283                 }
284
285                 object ReadValueVer2 (int type_index)
286                 {
287                         switch ((PredefinedResourceType)type_index)
288                         {
289                                 case PredefinedResourceType.Null:
290                                         return null;
291
292                                 case PredefinedResourceType.String:
293                                         return reader.ReadString();
294
295                                 case PredefinedResourceType.Bool:
296                                         return reader.ReadBoolean ();
297
298                                 case PredefinedResourceType.Char:
299                                         return (char)reader.ReadUInt16();
300
301                                 case PredefinedResourceType.Byte:
302                                         return reader.ReadByte();
303
304                                 case PredefinedResourceType.SByte:
305                                         return reader.ReadSByte();
306
307                                 case PredefinedResourceType.Int16:
308                                         return reader.ReadInt16();
309
310                                 case PredefinedResourceType.UInt16:
311                                         return reader.ReadUInt16();
312
313                                 case PredefinedResourceType.Int32:
314                                         return reader.ReadInt32();
315
316                                 case PredefinedResourceType.UInt32:
317                                         return reader.ReadUInt32();
318
319                                 case PredefinedResourceType.Int64:
320                                         return reader.ReadInt64();
321
322                                 case PredefinedResourceType.UInt64:
323                                         return reader.ReadUInt64();
324
325                                 case PredefinedResourceType.Single:
326                                         return reader.ReadSingle();
327
328                                 case PredefinedResourceType.Double:
329                                         return reader.ReadDouble();
330
331                                 case PredefinedResourceType.Decimal:
332                                         return reader.ReadDecimal();
333
334                                 case PredefinedResourceType.DateTime:
335                                         return new DateTime(reader.ReadInt64());
336
337                                 case PredefinedResourceType.TimeSpan:
338                                         return new TimeSpan(reader.ReadInt64());
339
340                                 case PredefinedResourceType.ByteArray:
341                                         return reader.ReadBytes (reader.ReadInt32 ());
342
343                                 case PredefinedResourceType.Stream:
344                                         // FIXME: create pinned UnmanagedMemoryStream for efficiency.
345                                         byte [] bytes = new byte [reader.ReadUInt32 ()];
346                                         reader.Read (bytes, 0, bytes.Length);
347                                         return new MemoryStream (bytes);
348                         }
349
350                         type_index -= (int)PredefinedResourceType.FistCustom;
351                         return ReadNonPredefinedValue (Type.GetType (typeNames[type_index], true));
352                 }
353
354                 object ReadValueVer1 (Type type)
355                 {
356                         // The most common first
357                         if (type==typeof(String))
358                                 return reader.ReadString();
359                         if (type==typeof(Int32))
360                                 return reader.ReadInt32();
361                         if (type==typeof(Byte))
362                                 return(reader.ReadByte());
363                         if (type==typeof(Double))
364                                 return(reader.ReadDouble());
365                         if (type==typeof(Int16))
366                                 return(reader.ReadInt16());
367                         if (type==typeof(Int64))
368                                 return(reader.ReadInt64());
369                         if (type==typeof(SByte))
370                                 return(reader.ReadSByte());
371                         if (type==typeof(Single))
372                                 return(reader.ReadSingle());
373                         if (type==typeof(TimeSpan))
374                                 return(new TimeSpan(reader.ReadInt64()));
375                         if (type==typeof(UInt16))
376                                 return(reader.ReadUInt16());
377                         if (type==typeof(UInt32))
378                                 return(reader.ReadUInt32());
379                         if (type==typeof(UInt64))
380                                 return(reader.ReadUInt64());
381                         if (type==typeof(Decimal))
382                                 return(reader.ReadDecimal());
383                         if (type==typeof(DateTime))
384                                 return(new DateTime(reader.ReadInt64()));
385
386                         return ReadNonPredefinedValue(type);
387                 }
388
389                 // TODO: Add security checks
390                 object ReadNonPredefinedValue (Type exp_type)
391                 {
392                         object obj=formatter.Deserialize(reader.BaseStream);
393                         if(obj.GetType() != exp_type) {
394                                 /* We got a bogus
395                                                  * object.  This
396                                                  * exception is the
397                                                  * best match I could
398                                                  * find.  (.net seems
399                                                  * to throw
400                                                  * BadImageFormatException,
401                                                  * which the docs
402                                                  * state is used when
403                                                  * file or dll images
404                                                  * cant be loaded by
405                                                  * the runtime.)
406                                                  */
407                                 throw new InvalidOperationException("Deserialized object is wrong type");
408                         }
409                         return obj;
410                 }               
411
412                 void LoadResourceValues (IList store)
413                 {
414                         ResourceInfo ri;
415                         ResourceCacheItem rci;
416                         object value;
417                         
418                         lock (readerLock) {
419                                 for (int i = 0; i < resourceCount; i++) {
420                                         ri = infos [i];
421                                         if (ri.TypeIndex == -1) {
422                                                 store.Add (new ResourceCacheItem (ri.ResourceName, null));
423                                                 continue;
424                                         }
425
426                                         reader.BaseStream.Seek (ri.ValuePosition, SeekOrigin.Begin);
427 #if NET_2_0
428                                         if (resource_ver == 2)
429                                                 value = ReadValueVer2 (ri.TypeIndex);
430                                         else
431 #endif
432                                                 value = ReadValueVer1 (Type.GetType (typeNames [ri.TypeIndex], true));
433
434                                         store.Add (new ResourceCacheItem (ri.ResourceName, value));
435                                 }
436                         }
437                 }
438                 
439 #if NET_2_0
440                 internal UnmanagedMemoryStream ResourceValueAsStream (string name, int index)
441                 {
442                         ResourceInfo ri = infos [index];
443                         if ((PredefinedResourceType)ri.TypeIndex != PredefinedResourceType.Stream)
444                                 throw new InvalidOperationException (String.Format ("Resource '{0}' was not a Stream. Use GetObject() instead.", name));
445                         
446                         lock (readerLock) {
447                                 reader.BaseStream.Seek (ri.ValuePosition, SeekOrigin.Begin);
448                                 
449                                 // here we return a Stream from exactly
450                                 // current position so that the returned
451                                 // Stream represents a single object stream.
452                                 long slen = reader.ReadInt32();
453                                 IntPtrStream basePtrStream = reader.BaseStream as IntPtrStream;
454                                 unsafe {
455                                         if (basePtrStream != null) {
456                                                 byte* addr = (byte*) basePtrStream.BaseAddress.ToPointer ();
457                                                 addr += basePtrStream.Position;
458                                                 return new UnmanagedMemoryStream ((byte*) (void*) addr, slen);
459                                         } else {
460                                                 IntPtr ptr = Marshal.AllocHGlobal ((int) slen);
461                                                 byte* addr = (byte*) ptr.ToPointer ();
462                                                 UnmanagedMemoryStream ms = new UnmanagedMemoryStream (addr, slen, slen, FileAccess.ReadWrite);
463                                                 // The memory resource must be freed
464                                                 // when the stream is disposed.
465                                                 ms.Closed += delegate (object o, EventArgs e) {
466                                                         Marshal.FreeHGlobal (ptr);
467                                                 };
468                                                 byte [] bytes = new byte [slen < 1024 ? slen : 1024];
469                                                 for (int i = 0; i < slen; i += bytes.Length) {
470                                                         int x = reader.Read (bytes, 0, bytes.Length);
471                                                         ms.Write (bytes, 0, x);
472                                                 }
473                                                 ms.Seek (0, SeekOrigin.Begin);
474                                                 return ms;
475                                         }
476                                 }
477                         }
478                 }
479 #endif
480
481                 public void Close ()
482                 {
483                         Dispose(true);
484                 }
485                 
486                 public IDictionaryEnumerator GetEnumerator () {
487                         if (reader == null){
488                                 throw new InvalidOperationException("ResourceReader is closed.");
489                         }
490                         else {
491                                 return new ResourceEnumerator (this);
492                         }
493                 }
494                 
495                 IEnumerator IEnumerable.GetEnumerator ()
496                 {
497                         return ((IResourceReader) this).GetEnumerator();
498                 }
499 #if NET_2_0
500                 public void GetResourceData (string resourceName, out string resourceType, out byte [] resourceData)
501                 {
502                         if (resourceName == null)
503                                 throw new ArgumentNullException ("resourceName");
504                         ResourceEnumerator en = new ResourceEnumerator (this);
505                         while (en.MoveNext ())
506                                 if ((string) en.Key == resourceName) {
507                                         GetResourceDataAt (en.Index, out resourceType, out resourceData);
508                                         return;
509                                 }
510                         throw new ArgumentException (String.Format ("Specified resource not found: {0}", resourceName));
511                 }
512
513                 private void GetResourceDataAt (int index, out string resourceType, out byte [] data)
514                 {
515                         ResourceInfo ri = infos [index];
516                         int type_index = ri.TypeIndex;
517                         if (type_index == -1)
518                                 throw new FormatException ("The resource data is corrupt");
519                         
520                         lock (readerLock) {
521                                 reader.BaseStream.Seek (ri.ValuePosition, SeekOrigin.Begin);
522                                 long pos2 = reader.BaseStream.Position;
523
524                                 // Simply read data, and seek back to the original position
525                                 if (resource_ver == 2) {
526                                         if (type_index >= (int) PredefinedResourceType.FistCustom) {
527                                                 int typenameidx = type_index - (int)PredefinedResourceType.FistCustom;
528                                                 if (typenameidx >= typeNames.Length)
529                                                         throw new FormatException ("The resource data is corrupt. Invalid index to types");
530                                                 resourceType = typeNames[typenameidx];
531                                         }
532                                         else
533                                                 resourceType = "ResourceTypeCode." + (PredefinedResourceType) type_index;
534                                         ReadValueVer2 (type_index);
535                                 } else {
536                                         // resource ver 1 == untyped
537                                         resourceType = "ResourceTypeCode.Null";
538                                         ReadValueVer1 (Type.GetType (typeNames [type_index], true));
539                                 }
540
541                                 // FIXME: the data size is wrong.
542                                 int datalen = (int) (reader.BaseStream.Position - pos2);
543                                 reader.BaseStream.Seek (-datalen, SeekOrigin.Current);
544                                 data = new byte [datalen];
545                                 reader.BaseStream.Read (data, 0, datalen);
546                         }
547                 }
548 #endif
549                 void IDisposable.Dispose ()
550                 {
551                         Dispose(true);
552                 }
553
554                 private void Dispose (bool disposing)
555                 {
556                         if(disposing) {
557                                 if(reader!=null) {
558                                         reader.Close();
559                                 }
560                         }
561
562                         reader=null;
563                         hashes=null;
564                         infos=null;
565                         typeNames=null;
566                 }
567                 
568                 internal class ResourceEnumerator : IDictionaryEnumerator
569                 {
570                         private ResourceReader reader;
571                         private int index = -1;
572                         private bool finished = false;
573                         ResourceCacheItem[] cache;
574                         
575                         internal ResourceEnumerator(ResourceReader readerToEnumerate)
576                         {
577                                 reader = readerToEnumerate;
578                                 FillCache ();
579                         }
580
581                         public int Index
582                         {
583                                 get { return index; }
584                         }
585
586                         public virtual DictionaryEntry Entry
587                         {
588                                 get {
589                                         if (reader.reader == null)
590                                                 throw new InvalidOperationException("ResourceReader is closed.");
591                                         if (index < 0)
592                                                 throw new InvalidOperationException("Enumeration has not started. Call MoveNext.");
593
594                                         DictionaryEntry entry = new DictionaryEntry();
595                                         entry.Key = Key;
596                                         entry.Value = Value;
597                                         return entry; 
598                                 }
599                         }
600                         
601                         public virtual object Key
602                         {
603                                 get { 
604                                         if (reader.reader == null)
605                                                 throw new InvalidOperationException("ResourceReader is closed.");
606                                         if (index < 0)
607                                                 throw new InvalidOperationException("Enumeration has not started. Call MoveNext.");
608
609                                         return cache [index].ResourceName;
610                                 }
611                         }
612                         
613                         public virtual object Value
614                         {
615                                 get { 
616                                         if (reader.reader == null)
617                                                 throw new InvalidOperationException("ResourceReader is closed.");
618                                         if (index < 0)
619                                                 throw new InvalidOperationException("Enumeration has not started. Call MoveNext.");
620                                         return cache [index].ResourceValue;
621                                 }
622                         }
623                         
624 #if NET_2_0
625                         public UnmanagedMemoryStream ValueAsStream
626                         {
627                                 get {
628                                         if (reader.reader == null)
629                                                 throw new InvalidOperationException("ResourceReader is closed.");
630                                         if (index < 0)
631                                                 throw new InvalidOperationException("Enumeration has not started. Call MoveNext.");
632                                         return(reader.ResourceValueAsStream((string) Key, index));
633                                 }
634                         }
635 #endif
636                         
637                         public virtual object Current
638                         {
639                                 get {
640                                         /* Entry does the checking, no
641                                          * need to repeat it here
642                                          */
643                                         return Entry; 
644                                 }
645                         }
646                         
647                         public virtual bool MoveNext ()
648                         {
649                                 if (reader.reader == null)
650                                         throw new InvalidOperationException("ResourceReader is closed.");
651                                 if (finished) {
652                                         return false;
653                                 }
654                                 
655                                 if (++index < reader.resourceCount){
656                                         return true;
657                                 }
658                                 else {
659                                         finished=true;
660                                         return false;
661                                 }
662                         }
663                         
664                         public void Reset () {
665                                 if (reader.reader == null)
666                                         throw new InvalidOperationException("ResourceReader is closed.");
667                                 index = -1;
668                                 finished = false;
669                         }
670
671                         void FillCache ()
672                         {
673                                 if (reader.reader == null)
674                                         return;
675                                 
676 #if NET_2_0
677                                 var resources = new List <ResourceCacheItem> (reader.resourceCount);
678 #else
679                                 ArrayList resources = new ArrayList (reader.resourceCount);
680 #endif
681                                 
682                                 reader.LoadResourceValues (resources);
683 #if NET_2_0
684                                 cache = resources.ToArray ();
685 #else
686                                 cache = (ResourceCacheItem[]) resources.ToArray (typeof (ResourceCacheItem));
687 #endif
688                         }
689                 } // internal class ResourceEnumerator
690         }  // public sealed class ResourceReader
691 } // namespace System.Resources