C++RAW #include "UnityPrefix.h" #include "Configuration/UnityConfigure.h" #include "Runtime/Graphics/Texture2D.h" #include "Runtime/Graphics/ImageConversion.h" #include "Runtime/Misc/Player.h" #include "Runtime/Export/WWW.h" #include "Runtime/Misc/WWWCached.h" #include "Runtime/Mono/MonoBehaviour.h" #include "Runtime/Scripting/ScriptingUtility.h" #include "Runtime/Scripting/ScriptingExportUtility.h" #include "Runtime/Scripting/Backend/ScriptingTypes.h" #include "Runtime/Scripting/ScriptingManager.h" #include "Runtime/Scripting/Scripting.h" #include "Runtime/Scripting/ScriptingObjectWithIntPtrField.h" #include "Runtime/Interfaces/IAudio.h" #if WEBPLUG #include "PlatformDependent/CommonWebPlugin/UnityWebStream.h" #include "PlatformDependent/CommonWebPlugin/CompressedFileStreamMemory.h" #endif #include "Runtime/Misc/AssetBundle.h" #include "Runtime/Serialize/PersistentManager.h" #include "Runtime/Misc/Player.h" #include "Runtime/Utilities/GUID.h" #include "Runtime/Misc/CachingManager.h" #include "Runtime/Misc/AssetBundleUtility.h" #if UNITY_EDITOR #include "Editor/Src/LicenseInfo.h" #include "Editor/Src/EditorUserBuildSettings.h" #endif #if UNITY_FLASH #include "PlatformDependent/FlashSupport/cpp/WWWFlash.h" #endif #if ENABLE_MOVIES #include "Runtime/Video/MovieTexture.h" #endif #if ENABLE_AUDIO #include "Runtime/Audio/AudioClip.h" #endif #include "Runtime/Misc/Player.h" #include "Runtime/Utilities/PathNameUtility.h" CSRAW using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; namespace UnityEngine { #if ENABLE_WWW // Simple access to web pages. CONDITIONAL ENABLE_WWW CLASS WWW : IDisposable // We are matching the WWW class here so we can directly access it. CSRAW internal IntPtr m_Ptr; C++RAW #if ENABLE_WWW inline WWW* GetWWWChecked (ScriptingObjectWithIntPtrField& self) { WWW* www = self.GetPtr(); if (!www) Scripting::RaiseNullException("WWW class has already been disposed."); return www; } #endif C++RAW #define GET GetWWWChecked (self) //*undocumented* CSRAW public void Dispose () { DestroyWWW(true); } CSRAW ~WWW() { DestroyWWW(false); } //*undocumented* THREAD_SAFE CUSTOM private void DestroyWWW(bool cancel) { WWW* www = self.GetPtr(); // no-op if already 0 self.SetPtr(0); if (www) { if (cancel) www->Cancel(); www->Release(); } } //*undocumented* CUSTOM void InitWWW( string url , byte[] postData, string[] iHeaders ) { string cpp_string = url; map headers; // Copy in headers from the MonoArray if available int headersSize = GetScriptingArraySize(iHeaders); for(int i=0; i < headersSize-1 ; i += 2) { headers[scripting_cpp_string_for(Scripting::GetScriptingArrayElementNoRef(iHeaders,i))] = scripting_cpp_string_for(Scripting::GetScriptingArrayElementNoRef(iHeaders,i+1)); } int rawPostDataLength = -1; char* rawPostDataPtr = NULL; if(postData != SCRIPTING_NULL) { rawPostDataPtr = Scripting::GetScriptingArrayStart(postData); // Will be copied by WWW::Create rawPostDataLength = GetScriptingArraySize(postData); } WWW* www = WWW::Create (cpp_string.c_str(), rawPostDataPtr, rawPostDataLength, headers); self.SetPtr(www); } // Creates a WWW request with the given URL. CSRAW public WWW(string url) { InitWWW(url, null, null); } // Creates a WWW request with the given URL. CONDITIONAL !UNITY_WEBGL CSRAW public WWW(string url, WWWForm form ) { string[] flattenedHeaders = FlattenedHeadersFrom(form.headers); #if UNITY_WEBPLAYER || UNITY_EDITOR if(enforceWebSecurityRestrictions()) { CheckSecurityOnHeaders(flattenedHeaders); } #endif InitWWW(url, form.data, flattenedHeaders); } // Creates a WWW request with the given URL. CSRAW public WWW(string url, byte[] postData) { InitWWW(url, postData, null); } // Creates a WWW request with the given URL. CSRAW #if !UNITY_METRO_API && !UNITY_WP8_API CSRAW public WWW(string url, byte[] postData, Hashtable headers ) { string[] flattenedHeaders = FlattenedHeadersFrom(headers); #if UNITY_WEBPLAYER || UNITY_EDITOR if(enforceWebSecurityRestrictions()) { CheckSecurityOnHeaders(flattenedHeaders); } #endif InitWWW(url, postData, flattenedHeaders); } CSRAW #else CSRAW public WWW(string url, byte[] postData, Dictionary headers ) { string[] flattenedHeaders = FlattenedHeadersFrom(headers); #if UNITY_WEBPLAYER || UNITY_EDITOR if(enforceWebSecurityRestrictions()) { CheckSecurityOnHeaders(flattenedHeaders); } #endif InitWWW(url, postData, flattenedHeaders); } CSRAW #endif CUSTOM internal bool enforceWebSecurityRestrictions() { #if UNITY_WEBPLAYER return true; #elif UNITY_EDITOR BuildTargetPlatform buildTarget = GetEditorUserBuildSettings().GetActiveBuildTarget(); return buildTarget == kBuildWebPlayerLZMA || buildTarget == kBuildWebPlayerLZMAStreamed; #else return false; #endif } // Encodes string into an URL-friendly format. CSRAW #if !UNITY_WEBGL public static string EscapeURL(string s, Encoding e=System.Text.Encoding.UTF8) { if (s == null) return null; if (s == "") return ""; if (e == null) return null; return WWWTranscoder.URLEncode(s,e); } #endif // Decodes string from an URL-friendly format. CSRAW #if !UNITY_WEBGL public static string UnEscapeURL(string s, Encoding e=System.Text.Encoding.UTF8) { if (null == s) return null; if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1) return s; return WWWTranscoder.URLDecode(s,e); } #endif // The headers from the HTTP response. CSRAW #if ENABLE_GENERICS public System.Collections.Generic.Dictionary responseHeaders { get { #if UNITY_FLASH UnityEngine.Flash.ActionScript.Import("System.UnityException"); #endif if (!isDone) throw new UnityException("WWW is not finished downloading yet"); return ParseHTTPHeaderString(responseHeadersString); } } #endif CUSTOM_PROP private string responseHeadersString { WWW& www = *GET; ScriptingStringPtr res = scripting_string_new(www.GetResponseHeaders().c_str()); return res; } // Returns the contents of the fetched web page as a string (RO). CONDITIONAL !UNITY_WEBGL CSRAW public string text { get { #if !UNITY_FLASH if (!isDone) throw new UnityException("WWW is not ready downloading yet"); return GetTextEncoder().GetString(this.bytes, 0, this.bytes.Length); #else //Flash can't access responsheaders correctly, so we always asume utf8 and use native parsing, directly from the bytearray, and let flash try and deal with it. return stringFromByteArray; #endif } } CSRAW internal static System.Text.Encoding DefaultEncoding { get { #if UNITY_WINRT return System.Text.Encoding.UTF8; #else return System.Text.Encoding.ASCII; #endif } } CONDITIONAL UNITY_FLASH CUSTOM_PROP internal string stringFromByteArray { WWWFlash *wwwflash = (WWWFlash*)GET; ScriptingString* str = scripting_string_new("");//We don't really care about the return string, as we'll emit as3 to parse bytearray below, no need to marshall the bytearray into native first. __asm __volatile__("var heapPos:int = heap.position;"); __asm __volatile__("heap.position = %0;"::"r"(wwwflash->m_Buffer)); __asm __volatile__("returnString = heap.readUTFBytes(%0); "::"r"(wwwflash->m_SizeLoaded)); __asm __volatile__("heap.position = heapPos;"); return str; } CONDITIONAL !UNITY_FLASH && !UNITY_WEBGL CSRAW private Encoding GetTextEncoder() { #if ENABLE_GENERICS // Check for charset type string contentType=null; if (responseHeaders.TryGetValue("CONTENT-TYPE",out contentType)) { int charsetKeyIndex = contentType.IndexOf("charset", StringComparison.OrdinalIgnoreCase); if (charsetKeyIndex > -1) { int charsetValueIndex = contentType.IndexOf('=', charsetKeyIndex); if (charsetValueIndex > -1) { string encoding = contentType.Substring(charsetValueIndex + 1).Trim().Trim(new []{'\'', '"'}).Trim(); int semicolonIndex = encoding.IndexOf(';'); if (semicolonIndex > -1) encoding = encoding.Substring(0, semicolonIndex); try { return System.Text.Encoding.GetEncoding(encoding); } catch (Exception) { Debug.Log("Unsupported encoding: '" + encoding + "'"); } } } } #endif // Use default (utf8) return System.Text.Encoding.UTF8; } FLUSHCONDITIONS CONDITIONAL !UNITY_FLASH && !UNITY_WEBGL OBSOLETE warning Please use WWW.text instead CSRAW public string data { get { return text; } } // Returns the contents of the fetched web page as a byte array (RO). CUSTOM_PROP byte[] bytes { WWW& www = *GET; if (www.GetType() == kWWWTypeCached) { ErrorString(kWWWCachedAccessError); return SCRIPTING_NULL; } if (www.GetSecurityPolicy() != WWW::kSecurityPolicyAllowAccess) Scripting::RaiseSecurityException("No valid crossdomain policy available to allow access"); if (!www.HasDownloadedOrMayBlock ()) return CreateEmptyStructArray(GetScriptingManager().GetCommonClasses().byte); return CreateScriptingArray( www.GetData(), www.GetSize(), GetScriptingManager().GetCommonClasses().byte ); } //*undocumented* OBSOLETE Can do the same with bytes.Length CUSTOM_PROP int size { WWW& www = *GET; if (!www.HasDownloadedOrMayBlock ()) return 0; return www.GetSize(); } //*undocumented* CONDITIONAL UNITY_WINRT CUSTOM private IntPtr GetError() { WWW *www = GET; if (www) return (void*)self->GetError(); else return (void*)kWWWErrCancelled; } // Returns an error message if there was an error during the download (RO). CSRAW #if UNITY_WINRT public string error { get { return Marshal.PtrToStringAnsi(GetError()); } } #endif // Returns an error message if there was an error during the download (RO). CONDITIONAL !UNITY_WINRT CUSTOM_PROP string error { WWW *www = GET; if (www) { const char* e = self->GetError(); if (e) return scripting_string_new(e); else return SCRIPTING_NULL; } else return scripting_string_new(kWWWErrCancelled); } //*undocumented* CUSTOM private Texture2D GetTexture(bool markNonReadable) { WWW& www = *GET; if (www.GetType() == kWWWTypeCached) { ErrorString(kWWWCachedAccessError); return SCRIPTING_NULL; } // create the texture Texture2D* tex = CreateObjectFromCode(); if (www.HasDownloadedOrMayBlock ()) { LoadMemoryBufferIntoTexture( *tex, self->GetData(), self->GetSize(), kLoadImageUncompressed, markNonReadable ); WWW::SecurityPolicy policy = self->GetSecurityPolicy(); if (policy != WWW::kSecurityPolicyAllowAccess) tex->SetReadAllowed(false); } else { LoadMemoryBufferIntoTexture( *tex, NULL, 0, kLoadImageUncompressed, markNonReadable ); } return Scripting::ScriptingWrapperFor(tex); } // Returns a [[Texture2D]] generated from the downloaded data (RO). CSRAW public Texture2D texture { get { return GetTexture(false); } } // Returns a non-readable [[Texture2D]] generated from the downloaded data (RO). CSRAW public Texture2D textureNonReadable { get { return GetTexture(true); } } // Returns a [[AudioClip]] generated from the downloaded data (RO). CONDITIONAL !UNITY_WEBGL && ENABLE_AUDIO CSRAW public AudioClip audioClip { get { return GetAudioClip(true); } } FLUSHCONDITIONS /// *listonly* CONDITIONAL !UNITY_WEBGL && ENABLE_AUDIO CSRAW public AudioClip GetAudioClip(bool threeD) { return GetAudioClip(threeD, false); } /// *listonly* CONDITIONAL !UNITY_WEBGL && ENABLE_AUDIO CSRAW public AudioClip GetAudioClip(bool threeD, bool stream) { return GetAudioClip(threeD, stream, AudioType.UNKNOWN); } // Returns an [[AudioClip]] generated from the downloaded data (RO). CONDITIONAL !UNITY_WEBGL && ENABLE_AUDIO CUSTOM public AudioClip GetAudioClip(bool threeD, bool stream, AudioType audioType) { IAudio *audio = GetIAudio(); if(audio == NULL) return SCRIPTING_NULL; WWW& www = *GET; if (www.GetType() == kWWWTypeCached) { ErrorString(kWWWCachedAccessError); return SCRIPTING_NULL; } AudioClip* clip = audio->CreateAudioClipFromWWW(*GET, threeD, stream, audioType); return Scripting::ScriptingWrapperFor (clip); } // Returns a [[MovieTexture]] generated from the downloaded data (RO). CONDITIONAL ENABLE_MOVIES CUSTOM_PROP MovieTexture movie { WWW& www = *GET; if (www.GetType() == kWWWTypeCached) { ErrorString(kWWWCachedAccessError); return SCRIPTING_NULL; } #if UNITY_EDITOR if (!LicenseInfo::Flag(lf_pro_version)) { ErrorString("Movie playback is only possible with Unity Pro"); return SCRIPTING_NULL; } #endif MovieTexture* tex = NULL; IAudio *audio = GetIAudio(); if(audio) tex = audio->CreateMovieTextureFromWWW(*GET); //Not applying any security restrictions here, because currently our API does not allow grabbing samples from the movieclip //It's impossible for a hacker to get his hands on the data, or xfer it somewhere. When we start supporting this, we should //add a crossdomain securitycheck here. return Scripting::ScriptingWrapperFor (tex); } // Replaces the contents of an existing [[Texture2D]] with an image from the downloaded data. CUSTOM void LoadImageIntoTexture(Texture2D tex) { WWW& www = *GET; if (www.GetType() == kWWWTypeCached) { ErrorString(kWWWCachedAccessError); return; } if (!www.HasDownloadedOrMayBlock ()) return; LoadMemoryBufferIntoTexture( *tex, www.GetData(), www.GetSize(), IsCompressedDXTTextureFormat(tex->GetTextureFormat())?kLoadImageDXTCompressDithered:kLoadImageUncompressed ); if (www.GetSecurityPolicy() != WWW::kSecurityPolicyAllowAccess) tex->SetReadAllowed(false); } // Is the download already finished? (RO) CUSTOM_PROP bool isDone { return (short)GET->IsDone(); } CONDITIONAL !UNITY_FLASH && !UNITY_WEBGL && !UNITY_WINRT OBSOLETE error All blocking WWW functions have been deprecated, please use one of the asynchronous functions instead. CUSTOM static string GetURL(string url) { map headers; const char* c_string = url.AsUTF8().c_str(); WWW* fetcher = WWW::Create(c_string, NULL, -1, headers); MonoString* result; if (fetcher->GetSecurityPolicy() != WWW::kSecurityPolicyAllowAccess) { Scripting::RaiseSecurityException("No valid crossdomain policy available to allow access"); return scripting_string_new(""); } if (!fetcher->HasDownloadedOrMayBlock ()) result = scripting_string_new(""); else result = scripting_string_new((char*)fetcher->GetData(), fetcher->GetSize()); fetcher->Release(); return result; } FLUSHCONDITIONS CSRAW #if !UNITY_FLASH && !UNITY_WEBGL && !UNITY_WINRT OBSOLETE error All blocking WWW functions have been deprecated, please use one of the asynchronous functions instead. #endif public static Texture2D GetTextureFromURL(string url) { return new WWW(url).texture; } // How far has the download progressed (RO). CUSTOM_PROP float progress { return GET->GetProgress(); } // How far has the upload progressed (RO). CUSTOM_PROP float uploadProgress { return GET->GetUploadProgress(); } // How many bytes have been downloaded (RO). CUSTOM_PROP int bytesDownloaded { return GET->GetSize(); } // Loads the new web player data file. CUSTOM void LoadUnityWeb () { WWW& www = *GET; if (!www.HasDownloadedOrMayBlock ()) return; if (www.GetSecurityPolicy() != WWW::kSecurityPolicyAllowAccess) { Scripting::RaiseSecurityException("No valid crossdomain policy available to allow access"); return; //is this return required? } #if WEBPLUG QueuePlayerLoadWebData (www.GetUnityWebStream()); www.GetUnityWebStream()->RetainDownload (&www); #else LogString (Format("Requested loading unity web file %s. This will only be loaded in the web player.", www.GetUrl ())); #endif } // Load an Ogg Vorbis file into the audio clip. CONDITIONAL !UNITY_FLASH && !UNITY_WEBGL && !UNITY_WINRT && ENABLE_AUDIO OBSOLETE warning .oggVorbis accessor is deprecated, use .audioClip or GetAudioClip() instead. CUSTOM_PROP AudioClip oggVorbis { IAudio *audio = GetIAudio(); if(audio == NULL) return SCRIPTING_NULL; if (audio->IsFormatSupportedByPlatform("ogg")) { ErrorString("Streaming of 'ogg' on this platform is not supported"); return SCRIPTING_NULL; } WWW& www = *GET; if (www.GetType() == kWWWTypeCached) { ErrorString(kWWWCachedAccessError); return SCRIPTING_NULL; } if (!www.HasDownloadedOrMayBlock ()) return SCRIPTING_NULL; AudioClip *clip = audio->CreateAudioClipOGGFromWWW(*GET); return Scripting::ScriptingWrapperFor(clip); } // The URL of this WWW request (RO). CUSTOM_PROP string url { return scripting_string_new(GET->GetUrl()); } // Streams an AssetBundle that can contain any kind of asset from the project folder. CUSTOM_PROP AssetBundle assetBundle { return Scripting::ScriptingWrapperFor (ExtractAssetBundle (*GET)); } // Priority of [[AssetBundle]] decompression thread. // SA: [[ThreadPriority]] enum. CONDITIONAL !UNITY_FLASH && !UNITY_WEBGL CUSTOM_PROP ThreadPriority threadPriority { return GET->GetThreadPriority(); } { GET->SetThreadPriority(value); } CUSTOM internal WWW (string url, int version, uint crc) { string cpp_string = url; #if ENABLE_CACHING WWW* www = new WWWCached(cpp_string.c_str(), version, crc); #else WWW* www = WWW::Create (cpp_string.c_str(), NULL, 0, WWW::WWWHeaders(), 0, crc); #endif self.SetPtr(www); } // Loads an AssetBundle with the specified version number from the cache. If the AssetBundle is not currently cached, it will automatically be downloaded and stored in the cache for future retrieval from local storage. CSRAW public static WWW LoadFromCacheOrDownload( string url, int version, uint crc = 0) { return new WWW(url, version, crc); } C++RAW #undef GET END // Helper class to generate form data to post to web servers using the [[WWW]] class. CONDITIONAL !UNITY_WEBGL CLASS WWWForm CSRAW private List formData; // CSRAW private List fieldNames; // CSRAW private List fileNames; // CSRAW private List types; // CSRAW private byte[] boundary; CSRAW private bool containsFiles = false; // Creates an empty WWWForm object. CSRAW public WWWForm() { formData = new List(); fieldNames = new List(); fileNames = new List(); types = new List(); // Generate a random boundary boundary=new byte[40]; for(int i=0; i<40; i++) { int randomChar=Random.Range(48,110); if(randomChar > 57) // skip unprintable chars between 57 and 64 (inclusive) randomChar+=7; if(randomChar > 90) // and 91 and 96 (inclusive) randomChar+=6; boundary[i]=(byte)randomChar; } } // Add a simple field to the form. CSRAW public void AddField(string fieldName, string value, Encoding e=System.Text.Encoding.UTF8) { fieldNames.Add(fieldName); fileNames.Add(null); formData.Add(e.GetBytes(value)); types.Add("text/plain; charset=\"" + e.WebName + "\""); } // Adds a simple field to the form. CSRAW public void AddField(string fieldName, int i) { AddField(fieldName, i.ToString()); } // Add binary data to the form. CSRAW public void AddBinaryData(string fieldName, byte[] contents, string fileName=null, string mimeType = null) { containsFiles=true; // We handle png files automatically as we suspect people will be uploading png files a lot due to the new // screen shot feature. If we want to add support for detecting other file types, we will need to do it in a more extensible way. bool isPng = contents.Length > 8 && contents[0] == 0x89 && contents[1] == 0x50 && contents[2] == 0x4e && contents[3] == 0x47 && contents[4] == 0x0d && contents[5] == 0x0a && contents[6] == 0x1a && contents[7] == 0x0a; if(fileName == null) { fileName = fieldName + (isPng?".png":".dat"); } if(mimeType == null) { if(isPng) mimeType="image/png"; else mimeType="application/octet-stream"; } fieldNames.Add(fieldName); fileNames.Add(fileName); formData.Add(contents); types.Add(mimeType); } // (RO) Returns the correct request headers for posting the form using the [[WWW]] class. CSRAW #if !UNITY_METRO_API && !UNITY_WP8_API CSRAW public Hashtable headers { get { Hashtable retval = new Hashtable(); if(containsFiles) retval["Content-Type"]="multipart/form-data; boundary=\"" + System.Text.Encoding.UTF8.GetString(boundary) + "\""; else retval["Content-Type"]="application/x-www-form-urlencoded"; return retval; } } CSRAW #else CSRAW public Dictionary headers { get { Dictionary retval = new Dictionary(); if(containsFiles) retval["Content-Type"]="multipart/form-data; boundary=\"" + System.Text.Encoding.UTF8.GetString(boundary, 0, boundary.Length) + "\""; else retval["Content-Type"]="application/x-www-form-urlencoded"; return retval; } } CSRAW #endif // (RO) The raw data to pass as the POST request body when sending the form. CSRAW public byte[] data { get { if(containsFiles) { byte[] dDash = WWW.DefaultEncoding.GetBytes("--"); byte[] crlf = WWW.DefaultEncoding.GetBytes("\r\n"); byte[] contentTypeHeader = WWW.DefaultEncoding.GetBytes("Content-Type: "); byte[] dispositionHeader = WWW.DefaultEncoding.GetBytes("Content-disposition: form-data; name=\""); byte[] endQuote = WWW.DefaultEncoding.GetBytes("\""); byte[] fileNameField = WWW.DefaultEncoding.GetBytes("; filename=\""); using(MemoryStream memStream = new MemoryStream(1024)) { for(int i=0; i < formData.Count; i++) { memStream.Write(crlf, 0, (int) crlf.Length); memStream.Write(dDash, 0, (int) dDash.Length); memStream.Write(boundary, 0, (int) boundary.Length); memStream.Write(crlf, 0, (int) crlf.Length); memStream.Write(contentTypeHeader, 0, (int) contentTypeHeader.Length); byte[] type=System.Text.Encoding.UTF8.GetBytes((string)types[i]); memStream.Write(type, 0, (int) type.Length); memStream.Write(crlf, 0, (int) crlf.Length); memStream.Write(dispositionHeader, 0, (int) dispositionHeader.Length); #if !UNITY_METRO_API && !UNITY_WP8_API string headerName = System.Text.Encoding.UTF8.HeaderName; #else string headerName = ""; #endif // Headers must be 7 bit clean, so encode as per rfc1522 using quoted-printable if needed. string encodedFieldName=(string)fieldNames[i]; if(!WWWTranscoder.SevenBitClean(encodedFieldName, System.Text.Encoding.UTF8) || encodedFieldName.IndexOf("=?") > -1) { encodedFieldName="=?"+headerName+"?Q?"+WWWTranscoder.QPEncode(encodedFieldName, System.Text.Encoding.UTF8) + "?="; } byte[] name=System.Text.Encoding.UTF8.GetBytes(encodedFieldName); memStream.Write(name, 0, (int) name.Length); memStream.Write(endQuote, 0, (int) endQuote.Length); if(fileNames[i] != null) { // Headers must be 7 bit clean, so encode as per rfc1522 using quoted-printable if needed. string encodedFileName=(string)fileNames[i]; if(!WWWTranscoder.SevenBitClean(encodedFileName, System.Text.Encoding.UTF8) || encodedFileName.IndexOf("=?") > -1) { encodedFileName="=?"+headerName+"?Q?"+WWWTranscoder.QPEncode(encodedFileName, System.Text.Encoding.UTF8) + "?="; } byte[] fileName=System.Text.Encoding.UTF8.GetBytes(encodedFileName); memStream.Write(fileNameField, 0, (int) fileNameField.Length); memStream.Write(fileName, 0, (int) fileName.Length); memStream.Write(endQuote, 0, (int) endQuote.Length); } memStream.Write(crlf, 0, (int) crlf.Length); memStream.Write(crlf, 0, (int) crlf.Length); byte[] formBytes = (byte[])formData[i]; memStream.Write(formBytes, 0, (int) formBytes.Length); } memStream.Write(crlf, 0, (int) crlf.Length); memStream.Write(dDash, 0, (int) dDash.Length); memStream.Write(boundary, 0, (int) boundary.Length); memStream.Write(dDash, 0, (int) dDash.Length); memStream.Write(crlf, 0, (int) crlf.Length); return memStream.ToArray(); } } else { byte[] ampersand = WWW.DefaultEncoding.GetBytes("&"); byte[] equal = WWW.DefaultEncoding.GetBytes("="); using(MemoryStream memStream = new MemoryStream(1024)) { for(int i=0; i < formData.Count; i++) { byte[] name=WWWTranscoder.URLEncode(System.Text.Encoding.UTF8.GetBytes((string)fieldNames[i])); byte[] formBytes = (byte[])formData[i]; byte[] value=WWWTranscoder.URLEncode(formBytes); if(i>0) memStream.Write(ampersand, 0, (int) ampersand.Length); memStream.Write(name, 0, (int) name.Length); memStream.Write(equal, 0, (int) equal.Length); memStream.Write(value, 0, (int) value.Length); } return memStream.ToArray(); } } } } END //*undocumented* CONDITIONAL !UNITY_WEBGL CLASS internal WWWTranscoder CSRAW private static byte [] ucHexChars = WWW.DefaultEncoding.GetBytes("0123456789ABCDEF"); CSRAW private static byte [] lcHexChars = WWW.DefaultEncoding.GetBytes("0123456789abcdef"); CSRAW private static byte urlEscapeChar=(byte)'%'; CSRAW private static byte urlSpace=(byte)'+'; CSRAW private static byte [] urlForbidden=WWW.DefaultEncoding.GetBytes("@&;:<>=?\"'/\\!#%+$,{}|^[]`"); CSRAW private static byte qpEscapeChar=(byte)'='; CSRAW private static byte qpSpace=(byte)'_'; CSRAW private static byte [] qpForbidden=WWW.DefaultEncoding.GetBytes("&;=?\"'%+_"); CSRAW private static byte Hex2Byte (byte[] b, int offset) { byte result=(byte)0; for (int i = offset; i < offset+2; i++ ) { result *= 16; int d=b[i]; if (d >= 48 && d <= 57) // 0 - 9 d -= 48; else if (d >= 65 && d <= 75) // A -F d -= 55; else if (d >= 97 && d <= 102) // a - f d -= 87; if (d>15) { return 63; // ? } result += (byte)d; } return result; } CSRAW private static byte[] Byte2Hex (byte b, byte[] hexChars) { byte[] dest= new byte[2]; dest[0]=hexChars[ b >> 4 ]; dest[1]=hexChars[ b &0xf ]; return dest; } CSRAW public static string URLEncode(string toEncode, Encoding e = Encoding.UTF8) { byte[] data = Encode(e.GetBytes(toEncode), urlEscapeChar, urlSpace, urlForbidden, false); return WWW.DefaultEncoding.GetString(data, 0, data.Length); } CSRAW public static byte[] URLEncode(byte[] toEncode) { return Encode(toEncode, urlEscapeChar, urlSpace, urlForbidden, false); } CSRAW public static string QPEncode(string toEncode, Encoding e = Encoding.UTF8) { byte[] data = Encode(e.GetBytes(toEncode), qpEscapeChar, qpSpace, qpForbidden, true); return WWW.DefaultEncoding.GetString(data, 0, data.Length); } CSRAW public static byte[] QPEncode(byte[] toEncode) { return Encode(toEncode, qpEscapeChar, qpSpace, qpForbidden, true); } CSRAW public static byte[] Encode(byte[] input, byte escapeChar, byte space, byte[] forbidden, bool uppercase) { using(MemoryStream memStream = new MemoryStream(input.Length*2)) { // encode for(int i=0; i < input.Length; i++) { if(input[i] == 32) { memStream.WriteByte(space); } else if(input[i] < 32 || input[i] > 126 || ByteArrayContains(forbidden, input[i])){ memStream.WriteByte(escapeChar); memStream.Write(Byte2Hex(input[i],uppercase?ucHexChars:lcHexChars),0,2); } else { memStream.WriteByte(input[i]); } } return memStream.ToArray(); } } CSRAW private static bool ByteArrayContains(byte[] array, byte b) { #if !UNITY_FLASH return (System.Array.IndexOf(array, b) != -1); #else for(int i = 0; i 126 ) return false; } return true; } END CSRAW [System.Obsolete ("this API is not for public use.")] public struct CacheIndex { public string name; public int bytesUsed; public int expires; } C++RAW struct MonoCacheIndex { ScriptingStringPtr name; int bytesUsed; int expires; }; // The Caching class lets you manage cached AssetBundles, downloaded using WWW::ref::LoadFromCacheOrDownload. CONDITIONAL ENABLE_CACHING CLASS Caching // (This is a WebPlayer-only function) CSRAW public static bool Authorize (string name, string domain, long size, string signature) { return Authorize(name, domain, size, -1, signature); } ///*listonly* CUSTOM static bool Authorize(string name, string domain, long size, int expiration, string signature) { return GetCachingManager().Authorize(name, domain, size, expiration, signature); } OBSOLETE warning Size is now specified as a long CSRAW public static bool Authorize(string name, string domain, int size, int expiration, string signature) { return Authorize(name, domain, (long)size, expiration, signature); } OBSOLETE warning Size is now specified as a long CSRAW public static bool Authorize (string name, string domain, int size, string signature) { return Authorize( name, domain, (long)size, signature); } // Delete all AssetBundle content that has been cached by the current application. CUSTOM static bool CleanCache () { if (GetCachingManager().GetAuthorizationLevel() >= CachingManager::kAuthorizationUser) return GetCachingManager().GetCurrentCache().CleanCache(); else { ErrorString("Unauthorized use of Caching API."); return false; } } OBSOLETE warning this API is not for public use. CUSTOM static bool CleanNamedCache (string name) { if (GetCachingManager().GetAuthorizationLevel() >= CachingManager::kAuthorizationAdmin) return GetCachingManager().CleanCache(name); else { ErrorString("Unauthorized use of Caching API."); return false; } } OBSOLETE warning This function is obsolete and has no effect. CUSTOM static bool DeleteFromCache (string url) { return false; } OBSOLETE warning This function is obsolete and will always return -1. Use IsVersionCached instead. CUSTOM static int GetVersionFromCache (string url) { return -1; } // Checks if an AssetBundle is cached. CUSTOM static bool IsVersionCached (string url, int version) { return GetCachingManager().IsCached(url, version); } // Bumps the timestamp of a cached file to be the current time. CUSTOM static bool MarkAsUsed (string url, int version) { return GetCachingManager().MarkAsUsed(url, version); } OBSOLETE warning this API is not for public use. CUSTOM_PROP static CacheIndex[] index { #if !UNITY_WINRT && ENABLE_WWW if (GetCachingManager().GetAuthorizationLevel() < CachingManager::kAuthorizationAdmin) { ErrorString("Unauthorized use of Caching API."); return NULL; } vector &indices = GetGlobalCachingManager().GetCacheIndices(); MonoArray *monoIndices = mono_array_new (mono_domain_get (), GetMonoManager().GetCommonClasses().cacheIndex, indices.size() ); for(int i=0; i(monoIndices, i).name = scripting_string_new (indices[i]->m_Name); GetMonoArrayElement(monoIndices, i).bytesUsed = indices[i]->m_BytesUsed; GetMonoArrayElement(monoIndices, i).expires = indices[i]->m_Expires; } return monoIndices; #else return SCRIPTING_NULL; #endif } // The number of currently unused bytes in the cache. CUSTOM_PROP static long spaceFree { return GetCachingManager().GetCachingDiskSpaceFree(); } // The total number of bytes that can potentially be allocated for caching. CUSTOM_PROP static long maximumAvailableDiskSpace { return GetCachingManager().GetMaximumDiskSpaceAvailable(); } { GetCachingManager().SetMaximumDiskSpaceAvailable(value); } // Used disk space in bytes. CUSTOM_PROP static long spaceOccupied { return GetCachingManager().GetCachingDiskSpaceUsed(); } OBSOLETE warning Please use Caching.spaceFree instead CUSTOM_PROP static int spaceAvailable { return GetCachingManager().GetCachingDiskSpaceFree(); } OBSOLETE warning Please use Caching.spaceOccupied instead CUSTOM_PROP static int spaceUsed { return GetCachingManager().GetCachingDiskSpaceUsed(); } // The number of seconds that an AssetBundle may remain unused in the cache before it is automatically deleted. CUSTOM_PROP static int expirationDelay { return GetCachingManager().GetExpirationDelay(); } { if (GetCachingManager().GetAuthorizationLevel() >= CachingManager::kAuthorizationUser) GetCachingManager().GetCurrentCache().SetExpirationDelay(value); } // Is Caching enabled? CUSTOM_PROP static bool enabled { return GetCachingManager().GetEnabled(); } { if (GetCachingManager().GetAuthorizationLevel() >= CachingManager::kAuthorizationAdmin) GetCachingManager().SetEnabled(value); else ErrorString("Unable to assign a value to Caching.enabled. This property is read-only."); } // Is caching ready? CUSTOM_PROP static bool ready { return GetCachingManager().GetIsReady(); } CONDITIONAL UNITY_IPHONE_API CUSTOM static void SetNoBackupFlag (string url, int version) { #if UNITY_IPHONE GetCachingManager().SetNoBackupFlag(url, version); #endif } CONDITIONAL UNITY_IPHONE_API CUSTOM static void ResetNoBackupFlag (string url, int version) { #if UNITY_IPHONE GetCachingManager().ResetNoBackupFlag(url, version); #endif } END CSRAW #endif //ENABLE_WWW CONDITIONAL !UNITY_FLASH && !UNITY_WEBGL && !UNITY_WINRT CLASS internal UnityLogWriter : System.IO.TextWriter THREAD_SAFE CUSTOM static void WriteStringToUnityLog(string s) { //this userstring could contains things like "%20", which we should make sure printf does not interpet //as if we wanted to print some argument. if (s.IsNull()) return; std::string utf8 = s.AsUTF8(); printf_console("%s",utf8.c_str()); } CSRAW public static void Init() { System.Console.SetOut(new UnityLogWriter()); } public override System.Text.Encoding Encoding { get { return System.Text.Encoding.UTF8; } } public override void Write(char value) { WriteStringToUnityLog(value.ToString()); } public override void Write(string s) { WriteStringToUnityLog(s); } END CLASS internal UnityString CSRAW public static string Format(string fmt, params object[] args) { return String.Format(fmt, args); } END }