 
 			if (params) {
 				for(var i:int = 0; i < params.length; ++i) {
-					if(params[i] is ByteArray) {
-						var length:uint = params[i].length;
-						// length + 1 for the added newline
-						stdin.writeUTFBytes(String(length + 1) + "\n");
-						stdin.writeBytes(params[i]);
-						stdin.writeUTFBytes("\n");
-					} else {
-						stdin.writeUTFBytes(String(params[i]) + "\n");
-					}
+					writeValue(stdin, params[i]);
 				}
 			}
 
 			return !_error;
 		}
 
-		private function waitForData(output:IDataInput):uint {
-			while(!output.bytesAvailable) {
-				// wait
+		private function writeValue(output:IDataOutput, value:*):void {
+			if(value is ByteArray) {
+				var length:uint = value.length;
+				// length + 1 for the added newline
+				output.writeUTFBytes(String(length + 1) + "\n");
+				output.writeBytes(value);
+				output.writeUTFBytes("\n");
+			} else if(value is String) {
+				output.writeUTFBytes(String(value.length + 1) + "\n" + value + "\n");
+			} else if(value is Array) {
+				output.writeUTFBytes(value.length + "\n");
+				for (var el:int = 0; el < value.length; ++el) {
+					writeValue(output, value[el]);
+				}
+			} else {
+				output.writeUTFBytes(String(value) + "\n");
+			}
+		}
+
+		private function waitForData(output:IDataInput, length:uint = 1):uint {
+			// copy over what's left from before
+			var tmpBuf:ByteArray = new ByteArray();
+			_buf.readBytes(tmpBuf);
+			_buf.clear();
+			tmpBuf.position = 0;
+			tmpBuf.readBytes(_buf);
+			_buf.position = 0;
+
+			while(_buf.length < length) {
+				// basically just wait for data
 				if(!_process.running) return 0;
-			}
-
-			return output.bytesAvailable;
+				output.readBytes(_buf);
+			}
+
+			_buf.position = 0;
+			return _buf.length;
+		}
+
+		private function readResponse():* {
+			if (!_process.running) return null;
+			var stdout:IDataInput = _process.standardOutput;
+
+			// first, wait for the length prefix
+			if (!waitForData(stdout)) return null;
+			var length:uint = _buf.readObject() as uint;
+
+			// AIR seems to have a limit of around 32k bytes data on stdin
+			// we can synchronously wait for, so for large data we use a temp
+			// file instead
+			if (length > 16384) {
+				var filename:String = readStringResponse();
+				if (!filename) return null;
+
+				var tmpfile:File = new File(filename);
+				var stream:FileStream = new FileStream();
+				stream.open(tmpfile, FileMode.READ);
+
+				// if we don't have enough data, we're unlikely to get it later,
+				// so just skip this call
+				var res:* = null;
+				if (stream.bytesAvailable >= length)
+					res = stream.readObject();
+
+				stream.close();
+				tmpfile.deleteFileAsync();
+				return res;
+			}
+
+			// now, wait for the actual data
+			if(!waitForData(stdout, length)) return null;
+
+			return _buf.readObject();
+
 		}
 
 		private function readBoolResponse():Boolean {
 			if(!_process.running) return false;
-			var stdout:IDataInput = _process.standardOutput;
-			var avail:uint = waitForData(stdout);
-
-			var response:String = stdout.readUTFBytes(1);
-			return (response == "t");
+			return readResponse() as Boolean;
 		}
 
 		private function readIntResponse():int {
 			if(!_process.running) return 0;
-			var stdout:IDataInput = _process.standardOutput;
-			var avail:uint = waitForData(stdout);
-
-			var response:String = stdout.readUTFBytes(avail);
-			return parseInt(response, 10);
+			return readResponse() as int;
 		}
 
 		private function readFloatResponse():Number {
-			if(!_process.running) return 0.0;
-			var stdout:IDataInput = _process.standardOutput;
-			var avail:uint = waitForData(stdout);
-
-			var response:String = stdout.readUTFBytes(avail)
-			return parseFloat(response);
+			if(!_process.running) return 0;
+			return readResponse() as Number;
 		}
 
 		private function readStringResponse():String {
 			if(!_process.running) return "";
-
-			var stdout:IDataInput = _process.standardOutput;
-			var avail:uint = waitForData(stdout);
-
-			var data:String = stdout.readUTFBytes(avail)
-			var newline:uint = data.indexOf("\n");
-			var buf:String = data.substring(newline + 1);
-			var length:uint = parseInt(data.substring(0, newline), 10);
-
-			while(buf.length < length) {
-				avail = waitForData(stdout);
-				buf += stdout.readUTFBytes(avail);
-			}
-
-			return buf;
+			return readResponse() as String;
 		}
 
 		private function eventDispatched(e:ProgressEvent):void {

package com.amanitadesign.steam {
	import flash.desktop.NativeProcess;
	import flash.desktop.NativeProcessStartupInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;

			if(!callWrapper(AIRSteam_SetCloudEnabledForApp, [enabled])) return false;
			return readBoolResponse();
		}

		public function getQuota():Array {
			if(!callWrapper(AIRSteam_GetQuota, [])) return null;
			return readResponse() as Array;
		}

		/* ugc/workshop */
		public function UGCDownload(handle:String, priority:int):Boolean {
			if(!callWrapper(AIRSteam_UGCDownload, [handle, priority])) return false;
			return readBoolResponse();
		}

		public function UGCRead(handle:String, size:int, offset:uint, data:ByteArray):Boolean {
			if(!callWrapper(AIRSteam_UGCRead, [handle, size, offset, data])) return false;
			var success:Boolean = readBoolResponse();

			if(success) {
				var response:ByteArray = readResponse() as ByteArray;
				data.writeBytes(response);
				data.position = 0;
			}

			return true;
		}

		public function getUGCDownloadProgress(handle:String):Array {
			if(!callWrapper(AIRSteam_GetUGCDownloadProgress, [handle])) return null;
			return readResponse() as Array;
		}

		public function getUGCDownloadResult(handle:String):DownloadUGCResult {
			if(!callWrapper(AIRSteam_GetUGCDownloadResult, [handle])) return null;
			return readResponse() as DownloadUGCResult;
		}

		public function publishWorkshopFile(name:String, preview:String, appId:uint, title:String, description:String, visibility:uint, tags:Array, fileType:uint):Boolean {
			if(!callWrapper(AIRSteam_PublishWorkshopFile, [name, preview, appId, title, description, visibility, tags, fileType])) return false;
			return readBoolResponse();
		}

		public function publishWorkshopFileResult():String {
			if(!callWrapper(AIRSteam_PublishWorkshopFileResult, [])) return "";
			return readStringResponse();
		}

		public function deletePublishedFile(file:String):Boolean {
			if(!callWrapper(AIRSteam_DeletePublishedFile, [file])) return false;
			return readBoolResponse();
		}

		public function getPublishedFileDetails(file:String):Boolean {
			if(!callWrapper(AIRSteam_GetPublishedFileDetails, [file])) return false;
			return readBoolResponse();
		}

		public function getPublishedFileDetailsResult(file:String):FileDetailsResult {
			if(!callWrapper(AIRSteam_GetPublishedFileDetailsResult, [file])) return null;
			return readResponse() as FileDetailsResult;
		}

		public function enumerateUserPublishedFiles(startIndex:uint):Boolean {
			if(!callWrapper(AIRSteam_EnumerateUserPublishedFiles, [startIndex])) return false;
			return readBoolResponse();
		}

		public function enumerateUserPublishedFilesResult():UserFilesResult {
			if(!callWrapper(AIRSteam_EnumerateUserPublishedFilesResult, [])) return null;
			return readResponse() as UserFilesResult;
		}

		public function enumeratePublishedWorkshopFiles(type:uint, start:uint, count:uint, days:uint, tags:Array, userTags:Array):Boolean {
			if(!callWrapper(AIRSteam_EnumeratePublishedWorkshopFiles, [type, start, count, days, tags, userTags])) return false;
			return readBoolResponse();
		}

		public function enumeratePublishedWorkshopFilesResult():WorkshopFilesResult {
			if(!callWrapper(AIRSteam_EnumeratePublishedWorkshopFilesResult, [])) return null;
			return readResponse() as WorkshopFilesResult;
		}

		public function enumerateUserSubscribedFiles(startIndex:uint):Boolean {
			if(!callWrapper(AIRSteam_EnumerateUserSubscribedFiles, [startIndex])) return false;
			return readBoolResponse();
		}

		public function enumerateUserSubscribedFilesResult():SubscribedFilesResult {
			if(!callWrapper(AIRSteam_EnumerateUserSubscribedFilesResult, [])) return null;
			return readResponse() as SubscribedFilesResult;
		}

		public function enumerateUserSharedWorkshopFiles(steamID:String, start:uint, required:Array, excluded:Array):Boolean {
			if(!callWrapper(AIRSteam_EnumerateUserSharedWorkshopFiles, [steamID, start, required, excluded])) return false;
			return readBoolResponse();
		}

		public function enumerateUserSharedWorkshopFilesResult():UserFilesResult {
			if(!callWrapper(AIRSteam_EnumerateUserSharedWorkshopFilesResult, [])) return null;
			return readResponse() as UserFilesResult;
		}

		public function enumeratePublishedFilesByUserAction(action:uint, startIndex:uint):Boolean {
			if(!callWrapper(AIRSteam_EnumeratePublishedFilesByUserAction, [action, startIndex])) return false;
			return readBoolResponse();
		}

		public function enumeratePublishedFilesByUserActionResult():FilesByUserActionResult {
			if(!callWrapper(AIRSteam_EnumeratePublishedFilesByUserActionResult, [])) return null;
			return readResponse() as FilesByUserActionResult;
		}

		public function subscribePublishedFile(file:String):Boolean {
			if(!callWrapper(AIRSteam_SubscribePublishedFile, [file])) return false;
			return readBoolResponse();
		}

		public function unsubscribePublishedFile(file:String):Boolean {
			if(!callWrapper(AIRSteam_UnsubscribePublishedFile, [file])) return false;
			return readBoolResponse();
		}

		public function createPublishedFileUpdateRequest(file:String):String {
			if(!callWrapper(AIRSteam_CreatePublishedFileUpdateRequest, [file])) return "";
			return readStringResponse();
		}

		public function updatePublishedFileFile(handle:String, file:String):Boolean {
			if(!callWrapper(AIRSteam_UpdatePublishedFileFile, [handle, file])) return false;
			return readBoolResponse();
		}

		public function updatePublishedFilePreviewFile(handle:String, preview:String):Boolean {
			if(!callWrapper(AIRSteam_UpdatePublishedFilePreviewFile, [handle, preview])) return false;
			return readBoolResponse();
		}

		public function updatePublishedFileTitle(handle:String, title:String):Boolean {
			if(!callWrapper(AIRSteam_UpdatePublishedFileTitle, [handle, title])) return false;
			return readBoolResponse();
		}

		public function updatePublishedFileDescription(handle:String, description:String):Boolean {
			if(!callWrapper(AIRSteam_UpdatePublishedFileDescription, [handle, description])) return false;
			return readBoolResponse();
		}

		public function updatePublishedFileSetChangeDescription(handle:String, changeDesc:String):Boolean {
			if(!callWrapper(AIRSteam_UpdatePublishedFileSetChangeDescription, [handle, changeDesc])) return false;
			return readBoolResponse();
		}

		public function updatePublishedFileVisibility(handle:String, visibility:uint):Boolean {
			if(!callWrapper(AIRSteam_UpdatePublishedFileVisibility, [handle, visibility])) return false;
			return readBoolResponse();
		}

		public function updatePublishedFileTags(handle:String, tags:Array):Boolean {
			if(!callWrapper(AIRSteam_UpdatePublishedFileTags, [handle, tags])) return false;
			return readBoolResponse();
		}

		public function commitPublishedFileUpdate(handle:String):Boolean {
			if(!callWrapper(AIRSteam_CommitPublishedFileUpdate, [handle])) return false;
			return readBoolResponse();
		}

		public function getPublishedItemVoteDetails(file:String):Boolean {
			if(!callWrapper(AIRSteam_GetPublishedItemVoteDetails, [file])) return false;
			return readBoolResponse();
		}

		public function getPublishedItemVoteDetailsResult():ItemVoteDetailsResult {
			if(!callWrapper(AIRSteam_GetPublishedItemVoteDetailsResult, [])) return null;
			return readResponse() as ItemVoteDetailsResult;
		}

		public function updateUserPublishedItemVote(file:String, upvote:Boolean):Boolean {
			if(!callWrapper(AIRSteam_UpdateUserPublishedItemVote, [file, upvote])) return false;
			return readBoolResponse();
		}

		public function setUserPublishedFileAction(file:String, action:uint):Boolean {
			if(!callWrapper(AIRSteam_SetUserPublishedFileAction, [file, action])) return false;
			return readBoolResponse();
		}

		/* overlay */
		public function activateGameOverlay(dialog:String):Boolean {
			if(!callWrapper(AIRSteam_ActivateGameOverlay, [dialog])) return false;
			return readBoolResponse();
		}

		public function activateGameOverlayToUser(dialog:String, steamId:String):Boolean {
			if(!callWrapper(AIRSteam_ActivateGameOverlayToUser, [dialog, steamId])) return false;
			return readBoolResponse();
		}

		public function activateGameOverlayToWebPage(url:String):Boolean {
			if(!callWrapper(AIRSteam_ActivateGameOverlayToWebPage, [url])) return false;
			return readBoolResponse();
		}

		public function activateGameOverlayToStore(appId:uint, flag:uint):Boolean {
			if(!callWrapper(AIRSteam_ActivateGameOverlayToStore, [appId, flag])) return false;
			return readBoolResponse();
		}

		public function activateGameOverlayInviteDialog(steamIdLobby:String):Boolean {
			if(!callWrapper(AIRSteam_ActivateGameOverlayInviteDialog, [steamIdLobby])) return false;
			return readBoolResponse();
		}

		public function isOverlayEnabled():Boolean {
			if(!callWrapper(AIRSteam_IsOverlayEnabled, [])) return false;
			return readBoolResponse();
		}

		/* DLC / subscriptions */
		public function isSubscribedApp(appId:uint):Boolean {
			if(!callWrapper(AIRSteam_IsSubscribedApp, [appId])) return false;
			return readBoolResponse();
		}

		public function isDLCInstalled(appId:uint):Boolean {
			if(!callWrapper(AIRSteam_IsDLCInstalled, [appId])) return false;
			return readBoolResponse();
		}

		public function getDLCCount():int {
			if(!callWrapper(AIRSteam_GetDLCCount, [])) return 0;
			return readIntResponse();
		}

		public function installDLC(appId:uint):Boolean {
			if(!callWrapper(AIRSteam_InstallDLC, [appId])) return false;
			return readBoolResponse();
		}

		public function uninstallDLC(appId:uint):Boolean {
			if(!callWrapper(AIRSteam_UninstallDLC, [appId])) return false;
			return readBoolResponse();
		}

		public function DLCInstalledResult():uint {
			if(!callWrapper(AIRSteam_DLCInstalledResult, [])) return 0;
			return readIntResponse();
		}
	}
}
