incubator-callback-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From purplecabb...@apache.org
Subject [39/50] [abbrv] git commit: Large aggregate commit mostly made of additions from Regis Merlino:
Date Wed, 17 Oct 2012 23:27:01 GMT
Large aggregate commit mostly made of additions from Regis Merlino:

- update of the shared Cordova JS code to 2.0
- implementation of storage, file and file transfer API groups

Plus some fixes:

- exec interface
- error handling
- video capture


Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/commit/7807de07
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/tree/7807de07
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/diff/7807de07

Branch: refs/heads/master
Commit: 7807de0725478704f404f2432141904cf2fa61af
Parents: fdef401
Author: Patrick Porlan <patrick.porlan@intel.com>
Authored: Wed Aug 8 15:29:55 2012 +0200
Committer: Patrick Porlan <patrick.porlan@intel.com>
Committed: Wed Aug 8 15:29:55 2012 +0200

----------------------------------------------------------------------
 Cordova/Cordova.vcxproj                |   21 +-
 Cordova/Cordova.vcxproj.filters        |   29 +
 Cordova/accel.c                        |    4 +-
 Cordova/capture.c                      |   52 +-
 Cordova/common.c                       |   89 +
 Cordova/common.h                       |   16 +
 Cordova/device.c                       |   25 +-
 Cordova/device.h                       |    2 +
 Cordova/file.c                         | 1280 +
 Cordova/file.h                         |   43 +
 Cordova/filetransfer.c                 |  486 +
 Cordova/filetransfer.h                 |   22 +
 Cordova/json.c                         |  545 +
 Cordova/json.h                         |   68 +
 Cordova/lib/js/platform.js             |   46 +
 Cordova/lib/js/plugin/win7/SQLError.js |   13 +
 Cordova/lib/js/plugin/win7/storage.js  |  300 +
 Cordova/lib/sqlite/sqlite3.c           |138243 +++++++++++++++++++++++++++
 Cordova/lib/sqlite/sqlite3.h           | 7055 ++
 Cordova/mp4patch.c                     |  172 +
 Cordova/mp4patch.h                     |   22 +
 Cordova/network.c                      |    2 +-
 Cordova/notification.c                 |  124 +-
 Cordova/platform.c                     |   42 +
 Cordova/platform.h                     |   22 +
 Cordova/shell.c                        |  179 +-
 Cordova/shell.h                        |   12 +-
 Cordova/storage.c                      |  384 +
 Cordova/storage.h                      |   22 +
 Cordova/www/capture.html               |    2 +-
 Cordova/www/cordova.win7.js            |  329 +-
 Cordova/www/file.html                  |   28 +
 Cordova/www/index.html                 |    2 +
 Cordova/www/notification.html          |    5 +-
 Cordova/www/storage.html               |   31 +
 35 files changed, 149480 insertions(+), 237 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/Cordova.vcxproj
----------------------------------------------------------------------
diff --git a/Cordova/Cordova.vcxproj b/Cordova/Cordova.vcxproj
index 2e4cbc0..6c79c0d 100644
--- a/Cordova/Cordova.vcxproj
+++ b/Cordova/Cordova.vcxproj
@@ -58,7 +58,6 @@
     <Link>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <ProjectReference />
@@ -83,7 +82,6 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <ProjectReference />
@@ -91,29 +89,46 @@
   <ItemGroup>
     <ClCompile Include="accel.c" />
     <ClCompile Include="capture.c" />
+    <ClCompile Include="common.c" />
     <ClCompile Include="device.c" />
+    <ClCompile Include="file.c" />
+    <ClCompile Include="filetransfer.c" />
     <ClCompile Include="jpeg.cpp" />
+    <ClCompile Include="json.c" />
+    <ClCompile Include="lib\sqlite\sqlite3.c" />
+    <ClCompile Include="mp4patch.c" />
     <ClCompile Include="network.c" />
     <ClCompile Include="notification.c" />
+    <ClCompile Include="platform.c" />
     <ClCompile Include="shell.c" />
+    <ClCompile Include="storage.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="accel.h" />
     <ClInclude Include="capture.h" />
     <ClInclude Include="common.h" />
     <ClInclude Include="device.h" />
+    <ClInclude Include="file.h" />
+    <ClInclude Include="filetransfer.h" />
     <ClInclude Include="jpeg.h" />
+    <ClInclude Include="json.h" />
+    <ClInclude Include="mp4patch.h" />
     <ClInclude Include="network.h" />
     <ClInclude Include="notification.h" />
+    <ClInclude Include="platform.h" />
     <ClInclude Include="resource.h" />
     <ClInclude Include="shell.h" />
+    <ClInclude Include="storage.h" />
   </ItemGroup>
   <ItemGroup>
     <None Include="lib\js\exec.js" />
     <None Include="lib\js\platform.js" />
     <None Include="lib\js\plugin\win7\device.js" />
     <None Include="lib\js\plugin\win7\jsHandler.js" />
+    <None Include="lib\js\plugin\win7\SQLError.js" />
+    <None Include="lib\js\plugin\win7\storage.js" />
     <None Include="toolbar.bmp" />
+    <None Include="www\acceleration.html" />
     <None Include="www\accel_game.css" />
     <None Include="www\accel_game.html" />
     <None Include="www\accel_game.js" />
@@ -121,9 +136,11 @@
     <None Include="www\cordova.win7.js" />
     <None Include="www\device.html" />
     <None Include="www\events.html" />
+    <None Include="www\file.html" />
     <None Include="www\index.html" />
     <None Include="www\network.html" />
     <None Include="www\notification.html" />
+    <None Include="www\storage.html" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="resource.rc" />

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/Cordova.vcxproj.filters
----------------------------------------------------------------------
diff --git a/Cordova/Cordova.vcxproj.filters b/Cordova/Cordova.vcxproj.filters
index 8bd1c26..9a634a6 100644
--- a/Cordova/Cordova.vcxproj.filters
+++ b/Cordova/Cordova.vcxproj.filters
@@ -8,6 +8,14 @@
     <ClCompile Include="network.c" />
     <ClCompile Include="shell.c" />
     <ClCompile Include="notification.c" />
+    <ClCompile Include="storage.c" />
+    <ClCompile Include="json.c" />
+    <ClCompile Include="lib\sqlite\sqlite3.c" />
+    <ClCompile Include="platform.c" />
+    <ClCompile Include="file.c" />
+    <ClCompile Include="common.c" />
+    <ClCompile Include="filetransfer.c" />
+    <ClCompile Include="mp4patch.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="accel.h" />
@@ -19,6 +27,12 @@
     <ClInclude Include="resource.h" />
     <ClInclude Include="shell.h" />
     <ClInclude Include="notification.h" />
+    <ClInclude Include="storage.h" />
+    <ClInclude Include="json.h" />
+    <ClInclude Include="platform.h" />
+    <ClInclude Include="file.h" />
+    <ClInclude Include="filetransfer.h" />
+    <ClInclude Include="mp4patch.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="resource.rc" />
@@ -37,6 +51,9 @@
     <None Include="lib\js\platform.js">
       <Filter>javascript</Filter>
     </None>
+    <None Include="www\acceleration.html">
+      <Filter>html</Filter>
+    </None>
     <None Include="www\index.html">
       <Filter>html</Filter>
     </None>
@@ -64,6 +81,18 @@
     <None Include="lib\js\plugin\win7\jsHandler.js">
       <Filter>javascript</Filter>
     </None>
+    <None Include="lib\js\plugin\win7\storage.js">
+      <Filter>javascript</Filter>
+    </None>
+    <None Include="www\storage.html">
+      <Filter>html</Filter>
+    </None>
+    <None Include="lib\js\plugin\win7\SQLError.js">
+      <Filter>javascript</Filter>
+    </None>
+    <None Include="www\file.html">
+      <Filter>html</Filter>
+    </None>
     <None Include="www\notification.html">
       <Filter>html</Filter>
     </None>

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/accel.c
----------------------------------------------------------------------
diff --git a/Cordova/accel.c b/Cordova/accel.c
index 0c8c45f..2a0749c 100644
--- a/Cordova/accel.c
+++ b/Cordova/accel.c
@@ -237,11 +237,11 @@ HRESULT accel_exec(BSTR callback_id, BSTR action, BSTR args, VARIANT *result)
 	if (!wcscmp(action, L"stop"))
 	{
 		stop_acquisition();
-		cordova_success_callback(callback_id, FALSE, NULL);
+		cordova_success_callback(callback_id, FALSE, NULL_MESSAGE);
 		return S_OK;
 	}
 
 	return DISP_E_MEMBERNOTFOUND;
 }
 
-DEFINE_CORDOVA_MODULE(Accelerometer, L"Accelerometer", accel_exec, NULL)
+DEFINE_CORDOVA_MODULE(Accelerometer, L"Accelerometer", accel_exec, NULL, NULL)

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/capture.c
----------------------------------------------------------------------
diff --git a/Cordova/capture.c b/Cordova/capture.c
index 5b9fc13..c28a053 100644
--- a/Cordova/capture.c
+++ b/Cordova/capture.c
@@ -34,6 +34,7 @@
 #include "resource.h"
 #include <wchar.h>
 #include "common.h"
+#include "mp4patch.h"
 
 #pragma comment(lib, "mfuuid.lib")      // Media Foundation UUIDs
 #pragma comment(lib, "mfplat.lib")	// MF attributes
@@ -87,11 +88,13 @@ HANDLE session_control_thread;
 
 #define MAX_FILE_NAME_LEN	255	// NUL not included
 
-#define PHOTO_OUTPUT_FILE		L"photo.jpg"
-#define VIDEO_OUTPUT_FILE		L"movie.mp4"
-
 wchar_t temp_directory_win[MAX_FILE_NAME_LEN + 1];	//	C:\Temp syntax
 wchar_t temp_directory_url[MAX_FILE_NAME_LEN + 8];	//	file://C:/Temp syntax
+wchar_t last_recorded_file_name_full[MAX_FILE_NAME_LEN+1];	// Full path
+wchar_t last_recorded_file_name[MAX_FILE_NAME_LEN+1];		// Name only
+
+LONGLONG start_time;	// Markers used to compute the duration of the last recording
+LONGLONG stop_time;
 
 // Note: the MPEG 4 sink is limited to 4 GB
 
@@ -758,7 +761,6 @@ HRESULT add_file_output_nodes (IMFTopology* topology_if, IMFTopologyNode** video
 	IMFTopologyNode* a_node_if = 0;
 	IMFByteStream* byte_stream_if = 0;
 
-	// MFCreateTempFile
 	hr = MFCreateFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, file_name, &byte_stream_if);
 
 	hr = MFCreateMPEG4MediaSink(byte_stream_if, h264_config_if, aac_config_if, &media_sink_if);
@@ -1219,6 +1221,7 @@ IMFTopology* build_topology (int topo_type)
 	// The topology will then be associated to a media session, and destroyed when the session completes
 	HRESULT hr;
 	IMFTopology* topology_if = 0;
+	SYSTEMTIME t;
 
 	hr = MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET);
 		
@@ -1240,14 +1243,11 @@ IMFTopology* build_topology (int topo_type)
 			break;
 
 		case VIDEO_CAPTURE_TOPO:
-			{
-				wchar_t fname[MAX_FILE_NAME_LEN+1];
-
-				swprintf(fname, MAX_FILE_NAME_LEN, L"%s%s", temp_directory_win, VIDEO_OUTPUT_FILE);
-				fname[MAX_FILE_NAME_LEN] = 0; // Our temp directories are not supposed to be this long...
-		
-				prepare_video_capture(topology_if, fname);
-			}
+			GetLocalTime(&t);
+			swprintf(last_recorded_file_name, MAX_FILE_NAME_LEN, L"%0d%02d%02d-%02d%02d%02d.mp4", t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
+			swprintf(last_recorded_file_name_full, MAX_FILE_NAME_LEN, L"%s%s", temp_directory_win, last_recorded_file_name);
+			last_recorded_file_name_full[MAX_FILE_NAME_LEN] = 0;
+			prepare_video_capture(topology_if, last_recorded_file_name_full);
 			break;
 		
 		case AUDIO_CAPTURE_TOPO:
@@ -1268,8 +1268,6 @@ unsigned int __stdcall session_control_proc(void* param)
 	HRESULT hr;
     PROPVARIANT var;
 	BOOL done = FALSE;
-	LONGLONG start_time = 0;
-	LONGLONG stop_time = 0;
 	IMFTopology* topology_if = (IMFTopology*) param;
 
 	CoInitialize(0);
@@ -1498,6 +1496,8 @@ void end_active_session (void)
 void stop_video_capture (void)
 {
 	end_active_session();
+
+	fix_mp4_duration(last_recorded_file_name_full, stop_time - start_time);
 }
 
 void stop_video_framing (void)
@@ -2177,18 +2177,20 @@ HRESULT STDMETHODCALLTYPE SGSC_OnShutdown(IMFSampleGrabberSinkCallback2 * This)
 
 HRESULT STDMETHODCALLTYPE  SGSC_OnProcessSampleEx (IMFSampleGrabberSinkCallback2 * This, REFGUID guidMajorMediaType, DWORD dwSampleFlags,
     LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE *pSampleBuffer, DWORD dwSampleSize, IMFAttributes *pAttributes)
-{	
+{
 	if (grab_first_available_frame)
 	{
-		wchar_t fname[MAX_FILE_NAME_LEN+1];
+		SYSTEMTIME t;
 
-		swprintf(fname, MAX_FILE_NAME_LEN, L"%s%s", temp_directory_win, PHOTO_OUTPUT_FILE);	
-		fname[MAX_FILE_NAME_LEN] = 0;
+		GetLocalTime(&t);
+		swprintf(last_recorded_file_name, MAX_FILE_NAME_LEN, L"%d%02d%02d-%02d%02d%02d.jpg", t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
+		swprintf(last_recorded_file_name_full, MAX_FILE_NAME_LEN, L"%s%s", temp_directory_win, last_recorded_file_name);
+		last_recorded_file_name_full[MAX_FILE_NAME_LEN] = 0;
 
 		if (mjpeg_mode)
 		{
 			// Direct JPEG frames
-			HANDLE h = CreateFile(fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
+			HANDLE h = CreateFile(last_recorded_file_name_full, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
 			DWORD written = 0;
 			WriteFile(h, pSampleBuffer, dwSampleSize, &written, 0);
 			CloseHandle(h);
@@ -2199,7 +2201,7 @@ HRESULT STDMETHODCALLTYPE  SGSC_OnProcessSampleEx (IMFSampleGrabberSinkCallback2
 			DWORD width = frame_size >> 32;
 			DWORD height = (DWORD) frame_size;
 
-			save_bitmap_as_jpeg(width, height, (unsigned char*) pSampleBuffer, dwSampleSize, fname, scan_len);
+			save_bitmap_as_jpeg(width, height, (unsigned char*) pSampleBuffer, dwSampleSize, last_recorded_file_name_full, scan_len);
 		}
 	
 		// Lower flag and don't try capturing another photo until it gets raised again
@@ -2263,14 +2265,10 @@ BSTR last_callback_id;
 
 void notify_capture_result (void)
 {
-	wchar_t filename[10 + MAX_FILE_NAME_LEN + 1];
 	wchar_t reply[30 + MAX_FILE_NAME_LEN + 1];
 
-	// Form suitable file name
-	swprintf(filename, sizeof(filename)/sizeof(filename[0]), L"%s%s", temp_directory_url, current_action_code == ACTION_PHOTO_CAPTURE ? PHOTO_OUTPUT_FILE : VIDEO_OUTPUT_FILE);
-	
 	// Send back our reply to the JS side
-	swprintf(reply, sizeof(reply)/sizeof(reply[0]), L"[{fullPath: '%s'}]", filename);
+	swprintf(reply, sizeof(reply)/sizeof(reply[0]), L"[{fullPath: '%s%s'}]", temp_directory_url, last_recorded_file_name);
 	
 	cordova_success_callback(last_callback_id, FALSE, reply);
 
@@ -2318,8 +2316,8 @@ HRESULT capture_exec(BSTR callback_id, BSTR action, BSTR args, VARIANT *result)
 	return DISP_E_MEMBERNOTFOUND;
 }
 
-DEFINE_CORDOVA_MODULE(Camera, L"Camera", camera_exec, NULL)
-DEFINE_CORDOVA_MODULE(Capture, L"Capture", capture_exec, NULL)
+DEFINE_CORDOVA_MODULE(Camera, L"Camera", camera_exec, NULL, NULL)
+DEFINE_CORDOVA_MODULE(Capture, L"Capture", capture_exec, NULL, NULL)
 
 
 // @@@ need to handle device lost events - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/common.c
----------------------------------------------------------------------
diff --git a/Cordova/common.c b/Cordova/common.c
new file mode 100644
index 0000000..a8df1ee
--- /dev/null
+++ b/Cordova/common.c
@@ -0,0 +1,89 @@
+// Copyright 2012 Intel Corporation
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+// 
+//    http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <malloc.h>
+#include <wchar.h>
+
+#include "common.h"
+
+#define TEXT_BUF_INC_SIZE 100
+
+struct _TextBuf {
+	wchar_t *wbuf;
+	size_t len;
+	size_t max;
+};
+
+TextBuf text_buf_new(void)
+{
+	return (TextBuf) calloc(1, sizeof(struct _TextBuf));
+}
+
+BOOL text_buf_append_len(TextBuf buf, const wchar_t *text, size_t text_len)
+{
+	size_t inc = (text_len > TEXT_BUF_INC_SIZE) ? text_len : TEXT_BUF_INC_SIZE;
+
+	// If needed, increase buf size
+	if (buf->len + text_len >= buf->max) {
+		void *ptr = realloc(buf->wbuf, sizeof(wchar_t) * (buf->max + inc + 1));
+		if (!ptr)
+			return FALSE;
+		buf->wbuf = (wchar_t *) ptr;
+	
+		buf->max += inc;
+	}
+
+	if (buf->len == 0)
+		buf->wbuf[0] = 0;
+
+	wcsncat_s(buf->wbuf + buf->len, buf->max - buf->len, text, text_len);
+	buf->len += text_len;
+	buf->wbuf[buf->len] = 0;
+
+	return TRUE;
+}
+
+BOOL text_buf_append(TextBuf buf, const wchar_t *text)
+{
+	return text_buf_append_len(buf, text, wcslen(text));
+}
+
+wchar_t *text_buf_get(const TextBuf buf)
+{
+	return buf->wbuf;
+}
+
+size_t text_buf_get_len(const TextBuf buf)
+{
+	return buf->len;
+}
+
+void text_buf_reset(TextBuf buf)
+{
+	buf->len = 0;
+}
+
+void text_buf_free(TextBuf buf)
+{
+	if (buf->wbuf)
+		free(buf->wbuf);
+	free(buf);
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/common.h
----------------------------------------------------------------------
diff --git a/Cordova/common.h b/Cordova/common.h
index ef44865..77d66df 100644
--- a/Cordova/common.h
+++ b/Cordova/common.h
@@ -18,3 +18,19 @@
 // under the License.
 
 #define CORDOVA_REG_KEY	L"Software\\Intel\\Cordova"
+
+#define ASSERT(x) if (!(x)) __debugbreak()
+
+struct _TextBuf;
+typedef struct _TextBuf *TextBuf;
+
+TextBuf text_buf_new(void);
+
+BOOL text_buf_append(TextBuf buf, const wchar_t *text);
+BOOL text_buf_append_len(TextBuf buf, const wchar_t *text, size_t text_len);
+
+wchar_t *text_buf_get(const TextBuf buf);
+size_t text_buf_get_len(const TextBuf buf);
+
+void text_buf_reset(TextBuf buf);
+void text_buf_free(TextBuf buf);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/device.c
----------------------------------------------------------------------
diff --git a/Cordova/device.c b/Cordova/device.c
index 66efb61..5479462 100644
--- a/Cordova/device.c
+++ b/Cordova/device.c
@@ -33,11 +33,20 @@
 #include "common.h"
 
 #define CORDOVA_MACHINE_ID		L"MachineID"
+#define CORDOVA_VERSION			L"2.0.0"
+#define CORDOVA_VERSION_LEN		5
 
 // A valid UUID string should look like this: f7b38bf1-2ece-4e2a-94a6-e791863f0109
 
 #define UUID_BUF_LEN_IN_BYTES (sizeof(wchar_t) * UUID_BUF_LEN)
 
+static wchar_t uuid[UUID_BUF_LEN];
+
+wchar_t *get_device_uuid(void)
+{
+	return uuid;
+}
+
 int acquire_unique_id(wchar_t buf[UUID_BUF_LEN])
 {
 	DWORD info;
@@ -102,23 +111,20 @@ int acquire_unique_id(wchar_t buf[UUID_BUF_LEN])
 static HRESULT get_device_info(BSTR callback_id)
 {
 	// Set initial Cordova global variables and fire up deviceready event
-	static wchar_t buf[100 + UUID_BUF_LEN + COMPUTER_NAME_BUF_LEN];
-	wchar_t uuid[UUID_BUF_LEN];
+	static wchar_t buf[100 + UUID_BUF_LEN + COMPUTER_NAME_BUF_LEN + CORDOVA_VERSION_LEN];
 	wchar_t computer_name[COMPUTER_NAME_BUF_LEN];
 	DWORD len = COMPUTER_NAME_BUF_LEN;
 	OSVERSIONINFOEX osver;
 	wchar_t* platform = L"Windows";
 
-	acquire_unique_id(uuid);
-
 	computer_name[0] = L'\0';
 	GetComputerName(computer_name, &len);
 
 	osver.dwOSVersionInfoSize = sizeof(osver);
 	GetVersionEx((LPOSVERSIONINFO)&osver);
 
-	wsprintf(buf, L"{uuid:'%s',name:'%s',platform:'%s',version:'%d.%d'}",
-				uuid, computer_name, platform, osver.dwMajorVersion, osver.dwMinorVersion);
+	wsprintf(buf, L"{uuid:'%s',name:'%s',platform:'%s',version:'%d.%d',cordova:'%s'}",
+				uuid, computer_name, platform, osver.dwMajorVersion, osver.dwMinorVersion, CORDOVA_VERSION);
 
 	cordova_success_callback(callback_id, FALSE, buf);
 
@@ -133,4 +139,9 @@ HRESULT device_exec(BSTR callback_id, BSTR action, BSTR args, VARIANT *result)
 	return DISP_E_MEMBERNOTFOUND;
 }
 
-DEFINE_CORDOVA_MODULE(Device, L"Device", device_exec, NULL)
\ No newline at end of file
+static void device_module_init(void)
+{
+	acquire_unique_id(uuid);
+}
+
+DEFINE_CORDOVA_MODULE(Device, L"Device", device_exec, device_module_init, NULL)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/device.h
----------------------------------------------------------------------
diff --git a/Cordova/device.h b/Cordova/device.h
index 3460f2b..01604e5 100644
--- a/Cordova/device.h
+++ b/Cordova/device.h
@@ -22,4 +22,6 @@
 #define UUID_BUF_LEN			(32+4+1)
 #define COMPUTER_NAME_BUF_LEN	100
 
+wchar_t *get_device_uuid(void);
+
 DECLARE_CORDOVA_MODULE(Device)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/file.c
----------------------------------------------------------------------
diff --git a/Cordova/file.c b/Cordova/file.c
new file mode 100644
index 0000000..63ba34d
--- /dev/null
+++ b/Cordova/file.c
@@ -0,0 +1,1280 @@
+// Copyright 2012 Intel Corporation
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+// 
+//    http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <Shlwapi.h>
+#include <Shlobj.h>
+#include <Shellapi.h>
+#include <wininet.h>
+#include <WinReg.h>
+
+#include "file.h"
+#include "common.h"
+#include "device.h"
+#include "json.h"
+
+#pragma comment(lib, "shlwapi.lib")
+
+static DWORD full_path_size;
+static wchar_t full_path[MAX_PATH + 1];
+static wchar_t url[INTERNET_MAX_URL_LENGTH + 1];
+
+static const wchar_t *temporary_dir;
+static const wchar_t *persistent_dir = L"persistent";
+#define MAX_CORDOVA_FS_NAME 32
+#define URL_START L"file:///"
+#define DRIVE_COLUMN_POS 9
+
+typedef enum {
+	TEMPORARY_FS = 0,
+	PERSISTENT_FS
+} CordovaFsType;
+
+static wchar_t temporary_root_path[MAX_PATH + 1];
+static wchar_t persistent_root_path[MAX_PATH + 1];
+
+// Tools
+// ---------------------------------------------------------------------------
+
+wchar_t *make_entry(BOOL is_dir, wchar_t *root_path, wchar_t *rel_path)
+{
+	wchar_t *response;
+	wchar_t name[MAX_PATH + 1];
+	const wchar_t *format = L"{isFile:%s,isDirectory:%s,name:'%s',fullPath:'%s'}";
+	size_t root_len = wcslen(root_path);
+	DWORD url_size = INTERNET_MAX_URL_LENGTH;
+
+	wcscpy_s(full_path, MAX_PATH, root_path);
+	if (rel_path && wcscmp(rel_path, L"\\"))
+		wcscat_s(full_path + root_len, MAX_PATH - root_len, rel_path);
+	if (UrlCreateFromPath(full_path, url, &url_size, 0) != S_OK)
+		return NULL;
+	url[DRIVE_COLUMN_POS] = L'_'; // Replace drive ':' due to wrong Cordova check in common/plugin/resolveLocalFileSystemURI.js file
+
+	// Comply with wrong unit test: replace %20 with space char
+	if (UrlUnescapeInPlace(url, 0) != S_OK)
+		return NULL;
+
+	if (rel_path && !wcscmp(rel_path, L"\\"))
+		wcscpy_s(name, MAX_PATH, L"/");
+	else
+		wcscpy_s(name, MAX_PATH, wcsrchr(full_path, L'\\') + 1);
+
+	response = (wchar_t *)malloc(sizeof(wchar_t) * (1 + wcslen(format) + 5 + 5 + wcslen(name) + wcslen(url)));
+	wsprintf(response, format, is_dir?L"false":L"true", is_dir?L"true":L"false", name, url);
+
+	return response;
+}
+
+static BOOL path_is_valid(wchar_t *path)
+{
+	size_t x = wcscspn(path, L"<>:\"/|?*");
+	if (x == wcslen(path))
+		return TRUE;
+
+	return FALSE;
+}
+
+CordovaFsError path_from_uri(wchar_t *uri, wchar_t *path, DWORD *len, BOOL must_exist, BOOL *is_dir)
+{
+	uri[DRIVE_COLUMN_POS] = L':'; // Restore drive ':'
+
+	if (PathCreateFromUrl(uri, path, len, 0) != S_OK)
+		return ENCODING_ERR;
+
+	if (!path_is_valid(path + 2)) // skip drive letter
+		return ENCODING_ERR;
+
+	if (wcsncmp(path, temporary_root_path, wcslen(temporary_root_path)) &&
+						wcsncmp(path, persistent_root_path, wcslen(persistent_root_path)))
+		return NOT_FOUND_ERR;
+
+	if (must_exist) {
+		DWORD attributes;
+
+		if ((attributes = GetFileAttributes(path)) == INVALID_FILE_ATTRIBUTES) {
+			return NOT_FOUND_ERR;
+		}
+
+		if (is_dir != NULL)
+			*is_dir = (attributes & FILE_ATTRIBUTE_DIRECTORY) ? TRUE : FALSE;
+	}
+
+	return FILE_NO_ERR;
+}
+
+static void file_fail_callback(wchar_t *callback_id, CordovaFsError err)
+{
+	wchar_t *error_text;
+
+	switch (err) {
+	case NOT_FOUND_ERR:
+		error_text = L"FileError.NOT_FOUND_ERR";
+		break;
+	case SECURITY_ERR:
+		error_text = L"FileError.SECURITY_ERR";
+		break;
+	case ABORT_ERR:
+		error_text = L"FileError.ABORT_ERR";
+		break;
+	case NOT_READABLE_ERR:
+		error_text = L"FileError.NOT_READABLE_ERR";
+		break;
+	case ENCODING_ERR:
+		error_text = L"FileError.ENCODING_ERR";
+		break;
+	case NO_MODIFICATION_ALLOWED_ERR:
+		error_text = L"FileError.NO_MODIFICATION_ALLOWED_ERR";
+		break;
+	case INVALID_STATE_ERR:
+		error_text = L"FileError.INVALID_STATE_ERR";
+		break;
+	case SYNTAX_ERR:
+		error_text = L"FileError.SYNTAX_ERR";
+		break;
+	case INVALID_MODIFICATION_ERR:
+		error_text = L"FileError.INVALID_MODIFICATION_ERR";
+		break;
+	case QUOTA_EXCEEDED_ERR:
+		error_text = L"FileError.QUOTA_EXCEEDED_ERR";
+		break;
+	case TYPE_MISMATCH_ERR:
+		error_text = L"FileError.TYPE_MISMATCH_ERR";
+		break;
+	case PATH_EXISTS_ERR:
+		error_text = L"FileError.PATH_EXISTS_ERR";
+		break;
+	default:
+		ASSERT(FALSE);
+	}
+
+	cordova_fail_callback(callback_id, FALSE, CB_GENERIC_ERROR, error_text);
+}
+
+time_t filetime_to_timet(FILETIME *ft) 
+{
+	ULARGE_INTEGER ull;
+
+	ull.LowPart = ft->dwLowDateTime;
+	ull.HighPart = ft->dwHighDateTime;
+
+	return ull.QuadPart / 10000000ULL - 11644473600ULL;
+}
+
+wchar_t *type_from_file_name(wchar_t *file_name)
+{
+	wchar_t *extension = wcsrchr(file_name, L'.');
+
+	if(extension) {
+		HKEY key;
+		DWORD data_size;
+		wchar_t *type;
+
+		if (RegOpenKeyEx(HKEY_CLASSES_ROOT, extension, 0, KEY_READ, &key) != ERROR_SUCCESS)
+			goto on_default;
+
+		if (RegQueryValueEx(key, L"Content Type", NULL, NULL, NULL, &data_size) != ERROR_SUCCESS)
+			goto on_default;
+
+		type = (wchar_t *)malloc(data_size + 1);
+		if (RegQueryValueEx(key, L"Content Type", NULL, NULL, (LPBYTE)type, &data_size) != ERROR_SUCCESS) {
+			free(type);
+			goto on_default;
+		}
+
+		RegCloseKey(key);
+		return type;
+	}
+
+on_default:
+	return _wcsdup(L"application/octetstream");
+}
+
+// FileSystem
+// ---------------------------------------------------------------------------
+
+static HRESULT request_file_system(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	JsonItem item;
+	CordovaFsType type;
+	UINT64 size;
+	wchar_t *response;
+	wchar_t *entry;
+	wchar_t *root;
+	const wchar_t *format = L"{name:'%s',root:%s}";
+	ULARGE_INTEGER available;
+
+	// Validate array contents
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_INT,
+											JSON_VALUE_INT64,
+											JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+
+	item = json_array_get_first(array);
+	type = (CordovaFsType) json_get_int_value(item);
+	item = json_array_get_next(item);
+	size = (UINT64) json_get_int64_value(item);
+
+	root = (type == TEMPORARY_FS) ? temporary_root_path : persistent_root_path;
+
+	if (GetDiskFreeSpaceEx(root, &available, NULL, NULL)) {
+		if (size > available.QuadPart) {
+			file_fail_callback(callback_id, QUOTA_EXCEEDED_ERR);
+			goto out;
+		}
+	}
+
+	entry = make_entry(TRUE, root, L"\\");
+	if (!entry) {
+		res = E_FAIL;
+		goto out;
+	}
+
+	response = (wchar_t *)malloc(sizeof(wchar_t) * (1 + MAX_CORDOVA_FS_NAME + wcslen(entry)));
+	wsprintf(response, format, (type == TEMPORARY_FS)?L"temporary":L"persistent", entry);
+	cordova_success_callback(callback_id, FALSE, response);
+
+	free(entry);
+	free(response);
+
+out:
+	json_free_args(array);
+
+	return res;
+}
+
+static HRESULT resolve_file_system_uri(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	wchar_t *uri = NULL;
+	wchar_t *entry;
+	BOOL is_dir;
+	CordovaFsError err;
+
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+												JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+
+	uri = json_get_string_value(array);
+	full_path_size = MAX_PATH;
+	err = path_from_uri(uri, full_path, &full_path_size, TRUE, &is_dir);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+
+	entry = make_entry(is_dir, full_path, NULL);
+	if (!entry) {
+		res = E_FAIL;
+		goto out;
+	}
+
+	cordova_success_callback(callback_id, FALSE, entry);
+	free(entry);
+
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+
+	return res;
+}
+
+// DirectoryReader
+// ---------------------------------------------------------------------------
+
+static HRESULT read_entries(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	wchar_t *uri = NULL;
+	BOOL is_dir;
+	CordovaFsError err;
+	HANDLE hFind = INVALID_HANDLE_VALUE;
+	WIN32_FIND_DATA ffd;
+	TextBuf response;
+	BOOL next;
+	wchar_t cur_path[MAX_PATH + 1];
+
+	response = text_buf_new();
+
+	// Check args
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+												JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+	
+	// Convert to path
+	uri = json_get_string_value(array);
+	full_path_size = MAX_PATH;
+	err = path_from_uri(uri, full_path, &full_path_size, TRUE, &is_dir);
+	if (err == FILE_NO_ERR && !is_dir)
+		err = TYPE_MISMATCH_ERR;
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+
+	// Read dir entries
+	wsprintf(cur_path, L"%s%s", full_path, L"*");
+
+	text_buf_append(response, L"[");
+
+	hFind = FindFirstFile(cur_path, &ffd);
+	if (INVALID_HANDLE_VALUE == hFind) 
+	{
+		if (GetLastError() == ERROR_FILE_NOT_FOUND) {
+			text_buf_append(response, L"]");
+			goto success;
+		}
+
+		res = E_FAIL;
+		goto out;
+	}
+
+	do {
+		wchar_t *entry = NULL;
+
+		wsprintf(cur_path, L"%s%s", full_path, ffd.cFileName);
+		if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+			if(wcscmp(ffd.cFileName, L".") && wcscmp(ffd.cFileName, L".."))
+				entry = make_entry(TRUE, cur_path, NULL);
+		}
+		else
+			entry = make_entry(FALSE, cur_path, NULL);
+
+		if (entry) {
+			text_buf_append(response, entry);
+			free(entry);
+		}
+
+		next = FindNextFile(hFind, &ffd);
+		if (next && entry) {
+			text_buf_append(response, L",");
+			entry = NULL;
+		}
+	} while (next);
+
+	FindClose(hFind);
+
+	text_buf_append(response, L"]");
+
+success:
+	FindClose(hFind);
+	cordova_success_callback(callback_id, FALSE, text_buf_get(response));
+
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+	text_buf_free(response);
+
+	return res;
+}
+
+// Entry
+// ---------------------------------------------------------------------------
+
+static HRESULT get_metadata(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	wchar_t *uri = NULL;
+
+	CordovaFsError err;
+	HANDLE hFind = INVALID_HANDLE_VALUE;
+	WIN32_FIND_DATA ffd;
+	wchar_t response[20];
+
+	// Check args
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+												JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+	
+	// Convert to path
+	uri = json_get_string_value(array);
+	full_path_size = MAX_PATH;
+	err = path_from_uri(uri, full_path, &full_path_size, TRUE, NULL);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+
+	// Get file info
+	hFind = FindFirstFile(full_path, &ffd);
+	if (INVALID_HANDLE_VALUE == hFind) {
+		if (GetLastError() == ERROR_FILE_NOT_FOUND) {
+			file_fail_callback(callback_id, NOT_FOUND_ERR);
+		} else {
+			res = E_FAIL;
+			goto out;
+		}
+	}
+
+	wsprintf(response, L"%I64d", filetime_to_timet(&ffd.ftLastWriteTime));
+	cordova_success_callback(callback_id, FALSE, response);
+
+	FindClose(hFind);
+
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+
+	return res;
+}
+
+static HRESULT move_or_copy_to(BSTR callback_id, BSTR args, BOOL is_move)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	JsonItem item;
+	wchar_t *uri = NULL;
+	TextBuf dst_uri = NULL;
+	wchar_t *str;
+	BOOL src_is_dir;
+	BOOL dst_is_dir;
+	CordovaFsError err;
+	wchar_t dest_path[MAX_PATH + 1];
+	wchar_t *entry;
+	SHFILEOPSTRUCT fileOp;
+
+	// Check args
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+										JSON_VALUE_STRING,
+										JSON_VALUE_STRING,
+										JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+	item = json_array_get_first(array);
+
+	// Convert source to path
+	uri = json_get_string_value(item);
+	full_path_size = MAX_PATH;
+	err = path_from_uri(uri, full_path, &full_path_size, TRUE, &src_is_dir);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+	if (!wcscmp(full_path, temporary_root_path) || !wcscmp(full_path, persistent_root_path)) {
+		file_fail_callback(callback_id, NO_MODIFICATION_ALLOWED_ERR);
+		goto out;
+	}
+
+	// Convert parent to path
+	item = json_array_get_next(item);
+	dst_uri = text_buf_new();
+
+	str = json_get_string_value(item);
+	text_buf_append(dst_uri, str);
+	free(str);
+
+	full_path_size = MAX_PATH;
+	err = path_from_uri(text_buf_get(dst_uri), dest_path, &full_path_size, TRUE, &dst_is_dir);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+	if (!dst_is_dir) {
+		file_fail_callback(callback_id, TYPE_MISMATCH_ERR);
+		goto out;
+	}
+
+	item = json_array_get_next(item);
+	text_buf_append(dst_uri, L"/");
+	str = json_get_string_value(item);
+	text_buf_append(dst_uri, str); // dest name
+
+	full_path_size = MAX_PATH;
+	err = path_from_uri(text_buf_get(dst_uri), dest_path, &full_path_size, FALSE, NULL);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+
+	if (!wcscmp(full_path, dest_path)) {
+		file_fail_callback(callback_id, INVALID_MODIFICATION_ERR);
+		goto out;
+	}
+
+	if ((!src_is_dir && PathFileExists(dest_path) && PathIsDirectory(dest_path)) ||
+				(src_is_dir && PathFileExists(dest_path) && PathIsDirectory(dest_path) && !PathIsDirectoryEmpty(dest_path)) ||
+				(src_is_dir && PathFileExists(dest_path) && !PathIsDirectory(dest_path))) {
+		file_fail_callback(callback_id, INVALID_MODIFICATION_ERR);
+		goto out;
+	}
+
+	// Special handling for moving dir to empty dir
+	if (src_is_dir && PathFileExists(dest_path) && PathIsDirectory(dest_path) && PathIsDirectoryEmpty(dest_path)) {
+		if (!RemoveDirectory(dest_path)) {
+			file_fail_callback(callback_id, INVALID_MODIFICATION_ERR);
+			goto out;
+		}
+	}
+
+	// Move or Copy
+	full_path[wcslen(full_path) + 1] = 0; // double-null terminated required by SHFileOperation()
+	dest_path[wcslen(dest_path) + 1] = 0; // double-null terminated required by SHFileOperation()
+	memset(&fileOp, 0, sizeof(SHFILEOPSTRUCT));
+	fileOp.wFunc = is_move?FO_MOVE:FO_COPY;
+	fileOp.pFrom = full_path;
+	fileOp.pTo = dest_path;
+	fileOp.fFlags = FOF_NO_UI;
+
+	if (SHFileOperation(&fileOp) != 0) {
+		file_fail_callback(callback_id, INVALID_MODIFICATION_ERR);
+		goto out;
+	}
+
+	entry = make_entry(src_is_dir, dest_path, NULL);
+	cordova_success_callback(callback_id, FALSE, entry);
+	free(entry);
+
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+	if (dst_uri)
+		text_buf_free(dst_uri);
+
+	return res;
+}
+
+static HRESULT move_to(BSTR callback_id, BSTR args)
+{
+	return move_or_copy_to(callback_id, args, TRUE);
+}
+
+static HRESULT copy_to(BSTR callback_id, BSTR args)
+{
+	return move_or_copy_to(callback_id, args, FALSE);
+}
+
+static HRESULT private_remove(BSTR callback_id, BSTR args, BOOL recursive)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	wchar_t *uri = NULL;
+	CordovaFsError err;
+	SHFILEOPSTRUCT fileOp;
+	BOOL is_dir;
+
+	// Check args
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+												JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+	
+	// Convert to path
+	uri = json_get_string_value(array);
+	full_path_size = MAX_PATH;
+	err = path_from_uri(uri, full_path, &full_path_size, TRUE, &is_dir);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+	if (!wcscmp(full_path, temporary_root_path) || !wcscmp(full_path, persistent_root_path)) {
+		file_fail_callback(callback_id, NO_MODIFICATION_ALLOWED_ERR);
+		goto out;
+	}
+
+	if (!recursive && is_dir && !PathIsDirectoryEmpty(full_path)) {
+		file_fail_callback(callback_id, INVALID_MODIFICATION_ERR);
+		goto out;
+	}
+
+	// Remove
+	full_path[wcslen(full_path) + 1] = 0; // double-null terminated required by SHFileOperation()
+	memset(&fileOp, 0, sizeof(SHFILEOPSTRUCT));
+	fileOp.wFunc = FO_DELETE;
+	fileOp.pFrom = full_path;
+	fileOp.fFlags = FOF_NO_UI;
+
+	if (SHFileOperation(&fileOp)) {
+		file_fail_callback(callback_id, NOT_FOUND_ERR);
+	}
+
+	cordova_success_callback(callback_id, FALSE, NULL_MESSAGE);
+
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+
+	return res;
+}
+
+static HRESULT remove(BSTR callback_id, BSTR args)
+{
+	return private_remove(callback_id, args, FALSE);
+}
+
+static HRESULT get_parent(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	wchar_t *uri = NULL;
+	CordovaFsError err;
+	wchar_t *entry;
+
+	// Check args
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+												JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+	
+	// Convert to path
+	uri = json_get_string_value(array);
+	full_path_size = MAX_PATH;
+	err = path_from_uri(uri, full_path, &full_path_size, TRUE, NULL);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+	if (wcscmp(full_path, temporary_root_path) && wcscmp(full_path, persistent_root_path))
+		*wcsrchr(full_path, L'\\') = 0;
+
+	// Get parent
+	entry = make_entry(TRUE, full_path, NULL);
+	cordova_success_callback(callback_id, FALSE, entry);
+	free(entry);
+
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+
+	return res;
+}
+
+// FileEntry
+// ---------------------------------------------------------------------------
+
+static HRESULT get_file_metadata(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	wchar_t *uri = NULL;
+	CordovaFsError err;
+	HANDLE hFind = INVALID_HANDLE_VALUE;
+	WIN32_FIND_DATA ffd;
+	wchar_t *format = L"{name:'%s',fullPath:'%s',type:'%s',lastModifiedDate:new Date(%I64d),size:%I64d}";
+	wchar_t *response;
+	ULARGE_INTEGER ull;
+	wchar_t *type = NULL;
+
+	// Check args
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+												JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+	
+	// Convert to path
+	uri = json_get_string_value(array);
+	full_path_size = MAX_PATH;
+	err = path_from_uri(uri, full_path, &full_path_size, TRUE, NULL);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+
+	// Get file info
+	hFind = FindFirstFile(full_path, &ffd);
+	if (INVALID_HANDLE_VALUE == hFind) {
+		if (GetLastError() == ERROR_FILE_NOT_FOUND) {
+			file_fail_callback(callback_id, NOT_FOUND_ERR);
+		} else {
+			res = E_FAIL;
+			goto out;
+		}
+	}
+
+	ull.LowPart = ffd.nFileSizeLow;
+	ull.HighPart = ffd.nFileSizeHigh;
+	type = type_from_file_name(ffd.cFileName);
+	uri[DRIVE_COLUMN_POS] = L'_'; // Replace drive ':'
+
+	// Build & send response
+	response = (wchar_t *)malloc(sizeof(wchar_t) * (1 + wcslen(format) + wcslen(ffd.cFileName) +
+									wcslen(uri) + wcslen(type) + 40));
+	wsprintf(response, format, ffd.cFileName, uri, type,
+								filetime_to_timet(&ffd.ftLastWriteTime), ull.QuadPart);
+	cordova_success_callback(callback_id, FALSE, response);
+
+	FindClose(hFind);
+	free(response);
+
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+	if (type)
+		free(type);
+
+	return res;
+}
+
+// DirectoryEntry
+// ---------------------------------------------------------------------------
+
+static HRESULT get_fs_object(BSTR callback_id, BSTR args, BOOL is_dir)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	JsonItem item;
+	wchar_t *uri = NULL;
+	CordovaFsError err;
+	JsonObjectItem options;
+	HANDLE hFind = INVALID_HANDLE_VALUE;
+	WIN32_FIND_DATA ffd;
+	BOOL option_create = FALSE;
+	BOOL option_exclusive = FALSE;
+	JsonObjectItem object;
+	wchar_t *entry;
+
+	// Check args
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+												JSON_VALUE_STRING,
+												JSON_VALUE_OBJECT | JSON_VALUE_NULL,
+												JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+	item = json_array_get_first(array);
+	
+	// Convert src uri to path
+	uri = json_get_string_value(item);
+	full_path_size = MAX_PATH;
+	err = path_from_uri(uri, full_path, &full_path_size, TRUE, NULL);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+
+	// Convert dst uri to path
+	item = json_array_get_next(item);
+	free(uri);
+
+	uri = json_get_string_value(item);
+
+	if (!wcsncmp(uri, URL_START, wcslen(URL_START))) { // absolute path
+		full_path_size = MAX_PATH;
+		err = path_from_uri(uri, full_path, &full_path_size, FALSE, NULL);
+		if (err != FILE_NO_ERR) {
+			file_fail_callback(callback_id, err);
+			goto out;
+		}
+
+		if (!wcscmp(full_path, temporary_root_path) || !wcscmp(full_path, persistent_root_path)) {
+			file_fail_callback(callback_id, NO_MODIFICATION_ALLOWED_ERR);
+			goto out;
+		}
+	} else { // relative to src path
+		wchar_t *ptr = uri;
+
+		while (*ptr++) {
+			if (*ptr == L'/')
+				*ptr = L'\\';
+		}
+
+		if (!path_is_valid(uri)) {
+			file_fail_callback(callback_id, ENCODING_ERR);
+			goto out;
+		}
+
+		if (!PathAppend(full_path, uri)) {
+			file_fail_callback(callback_id, ENCODING_ERR);
+			goto out;
+		}
+	}
+
+	item = json_array_get_next(item);
+	if (json_get_value_type(item) != JSON_VALUE_NULL) {
+		options = json_object_get_first(json_get_object_value(item));
+		object = json_object_find_prop(options, L"create", JSON_VALUE_BOOL);
+		if (object)
+			option_create = json_get_bool_value(to_item(object));
+
+		object = json_object_find_prop(options, L"exclusive", JSON_VALUE_BOOL);
+		if (object)
+			option_exclusive = json_get_bool_value(to_item(object));
+	}
+
+	// Get file info
+	hFind = FindFirstFile(full_path, &ffd);
+	if (INVALID_HANDLE_VALUE == hFind) {
+		DWORD err = GetLastError();
+		if (err == ERROR_INVALID_NAME) {
+			file_fail_callback(callback_id, ENCODING_ERR);
+			goto out;
+		}
+
+		if (option_create) {
+			if (is_dir) {
+				if (!SUCCEEDED(SHCreateDirectory(NULL,full_path))) {
+					res = E_FAIL;
+					goto out;
+				}
+			} else {
+				 HANDLE file;
+				if ((file = CreateFile(full_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
+					res = E_FAIL;
+					goto out;
+				}
+				CloseHandle(file);
+			}
+		} else {
+			file_fail_callback(callback_id, NOT_FOUND_ERR);
+			goto out;
+		}
+	} else { // exists
+		if (option_create && option_exclusive) {
+			file_fail_callback(callback_id, PATH_EXISTS_ERR);
+			goto out;
+		}
+		if (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)?TRUE:FALSE) != is_dir) {
+			file_fail_callback(callback_id, TYPE_MISMATCH_ERR);
+			goto out;
+		}
+	}
+
+	// Return entry
+	entry = make_entry(TRUE, full_path, NULL);
+	cordova_success_callback(callback_id, FALSE, entry);
+	free(entry);
+
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+
+	return res;
+}
+
+static HRESULT get_directory(BSTR callback_id, BSTR args)
+{
+	return get_fs_object(callback_id, args, TRUE);
+}
+
+static HRESULT get_file(BSTR callback_id, BSTR args)
+{
+	return get_fs_object(callback_id, args, FALSE);
+}
+
+static HRESULT remove_recursively(BSTR callback_id, BSTR args)
+{
+	return private_remove(callback_id, args, TRUE);
+}
+
+// FileReader
+// ---------------------------------------------------------------------------
+
+static HRESULT read_file(BSTR callback_id, wchar_t *uri, wchar_t *encoding, BOOL is_base64)
+{
+	HRESULT res = S_OK;
+	CordovaFsError err;
+	HANDLE file = INVALID_HANDLE_VALUE;
+	ULARGE_INTEGER file_size;
+	BOOL is_dir;
+	char *buf = NULL;
+	int utf16_len;
+	wchar_t *utf16_text = NULL;
+	DWORD read;
+	wchar_t *base64_prefix = L"data:text/plain;base64,";
+	size_t extra_len = is_base64?wcslen(base64_prefix):0;
+	
+	// Convert src uri to path
+	full_path_size = MAX_PATH;
+	err = path_from_uri(uri, full_path, &full_path_size, TRUE, &is_dir);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+
+	if (is_dir) {
+		file_fail_callback(callback_id, TYPE_MISMATCH_ERR);
+		goto out;
+	}
+
+	// Open file
+	file = CreateFile(full_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (file == INVALID_HANDLE_VALUE) {
+		file_fail_callback(callback_id, INVALID_MODIFICATION_ERR);
+		goto out;
+	}
+
+	// Read file contents
+	file_size.LowPart = GetFileSize(file, &file_size.HighPart);
+	if (file_size.HighPart) {
+		file_fail_callback(callback_id, ABORT_ERR);
+		goto out;
+	}
+
+	buf = (char *) malloc(file_size.LowPart + 1);
+	buf[file_size.LowPart] = 0;
+	if (!ReadFile(file, buf, file_size.LowPart, &read, NULL)) {
+		file_fail_callback(callback_id, ABORT_ERR);
+		goto out;
+	}
+
+	// Convert buffer
+	if (_wcsicmp(encoding, L"UTF-8")) {
+		file_fail_callback(callback_id, ABORT_ERR);
+		goto out;
+	}
+
+	utf16_len = MultiByteToWideChar(CP_UTF8, 0, buf, -1, NULL, 0); // First call to get length
+	utf16_text = (wchar_t *) malloc(sizeof(wchar_t) * (2 + utf16_len + extra_len));
+	utf16_text[1 + utf16_len + extra_len] = 0;
+	if (!MultiByteToWideChar(CP_UTF8, 0, buf, -1, utf16_text + 1 + extra_len, utf16_len)) {
+		file_fail_callback(callback_id, ABORT_ERR);
+		goto out;
+	}
+
+	utf16_text[0] = L'\'';
+	if (is_base64) 
+		memcpy(utf16_text + 1, base64_prefix, sizeof(wchar_t) * wcslen(base64_prefix));
+	utf16_text[utf16_len + extra_len] = L'\'';
+	cordova_success_callback(callback_id, FALSE, utf16_text);
+
+out:
+	if (buf)
+		free(buf);
+	if (utf16_text)
+		free(utf16_text);
+	if (file != INVALID_HANDLE_VALUE)
+		CloseHandle(file);
+
+	return res;
+}
+
+static HRESULT read_as_text(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	JsonItem item;
+	wchar_t *uri = NULL;
+	wchar_t *encoding = NULL;
+
+		// Check args
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+												JSON_VALUE_STRING,
+												JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+
+	item = json_array_get_first(array);
+	uri = json_get_string_value(item);
+	item = json_array_get_next(item);
+	encoding = json_get_string_value(item);
+	
+	res = read_file(callback_id, uri, encoding, FALSE);
+
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+	if (encoding)
+		free(encoding);
+
+	return res;
+}
+
+static HRESULT read_as_data_url(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	wchar_t *uri = NULL;
+
+		// Check args
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+												JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+
+	uri = json_get_string_value(array);
+	
+	res = read_file(callback_id, uri, L"UTF-8", TRUE);
+
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+
+	return res;
+}
+
+// FileWriter
+// ---------------------------------------------------------------------------
+
+static HRESULT write(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	JsonItem item;
+	wchar_t *uri = NULL;
+	CordovaFsError err;
+	HANDLE file = INVALID_HANDLE_VALUE;
+	char *utf8_text = NULL;
+	int utf8_len;
+	DWORD written;
+	LARGE_INTEGER seek;
+	wchar_t response[20];
+	wchar_t *data = NULL;
+
+	// Check args
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+												JSON_VALUE_STRING,
+												JSON_VALUE_INT64,
+												JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+	item = json_array_get_first(array);
+	
+	// Convert src uri to path
+	uri = json_get_string_value(item);
+	full_path_size = MAX_PATH;
+	err = path_from_uri(uri, full_path, &full_path_size, FALSE, NULL);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+
+	// Open file
+	file = CreateFile(full_path, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (file == INVALID_HANDLE_VALUE) {
+		file_fail_callback(callback_id, INVALID_MODIFICATION_ERR);
+		goto out;
+	}
+
+	// Write file
+	item = json_array_get_next(item);
+	data = json_get_string_value(item);
+	utf8_len = WideCharToMultiByte(CP_UTF8, 0, data, wcslen(data), NULL, 0, NULL, NULL); // First call to get length
+	utf8_text = (char *) malloc(utf8_len + 1);
+	if (!WideCharToMultiByte(CP_UTF8, 0, data, wcslen(data), utf8_text, utf8_len, NULL, NULL)) {
+		file_fail_callback(callback_id, ABORT_ERR);
+		goto out;
+	}
+
+	item = json_array_get_next(item);
+	seek.QuadPart = json_get_int64_value(item);
+	if (!SetFilePointerEx(file, seek, NULL, FILE_BEGIN)) {
+		file_fail_callback(callback_id, INVALID_MODIFICATION_ERR);
+		goto out;
+	}
+
+	if (!WriteFile(file, utf8_text, utf8_len, &written, NULL)) {
+		file_fail_callback(callback_id, ABORT_ERR);
+		goto out;
+	}
+
+	wsprintf(response, L"%d", written);
+	cordova_success_callback(callback_id, FALSE, response);
+
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+	if (data)
+		free(data);
+	if (utf8_text)
+		free(utf8_text);
+	if (file != INVALID_HANDLE_VALUE)
+		CloseHandle(file);
+
+	return res;
+}
+
+static HRESULT truncate(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	JsonItem item;
+	wchar_t *uri = NULL;
+	CordovaFsError err;
+	HANDLE file = INVALID_HANDLE_VALUE;
+	LARGE_INTEGER seek;
+	wchar_t response[20];
+	BOOL is_dir;
+
+	// Check args
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,
+												JSON_VALUE_INT64,
+												JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+	item = json_array_get_first(array);
+	
+	// Convert src uri to path
+	uri = json_get_string_value(item);
+	full_path_size = MAX_PATH;
+	err = path_from_uri(uri, full_path, &full_path_size, TRUE, &is_dir);
+	if (err != FILE_NO_ERR) {
+		file_fail_callback(callback_id, err);
+		goto out;
+	}
+
+	if (is_dir) {
+		file_fail_callback(callback_id, TYPE_MISMATCH_ERR);
+		goto out;
+	}
+
+	// Open file
+	file = CreateFile(full_path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (file == INVALID_HANDLE_VALUE) {
+		file_fail_callback(callback_id, INVALID_MODIFICATION_ERR);
+		goto out;
+	}
+
+	// Truncate file
+	item = json_array_get_next(item);
+	seek.QuadPart = json_get_int64_value(item);
+	if (!SetFilePointerEx(file, seek, NULL, FILE_BEGIN)) {
+		file_fail_callback(callback_id, INVALID_MODIFICATION_ERR);
+		goto out;
+	}
+
+	if (!SetEndOfFile(file)) {
+		file_fail_callback(callback_id, INVALID_MODIFICATION_ERR);
+		goto out;
+	}
+
+	wsprintf(response, L"%I64d", seek.QuadPart);
+	cordova_success_callback(callback_id, FALSE, response);
+out:
+	json_free_args(array);
+	if (uri)
+		free(uri);
+	if (file != INVALID_HANDLE_VALUE)
+		CloseHandle(file);
+
+	return res;
+}
+
+// Module
+// ---------------------------------------------------------------------------
+
+static HRESULT file_module_exec(BSTR callback_id, BSTR action, BSTR args, VARIANT *result)
+{
+	// FileSystem
+	if (!wcscmp(action, L"requestFileSystem"))
+			return request_file_system(callback_id, args);
+	if (!wcscmp(action, L"resolveLocalFileSystemURI"))
+		return resolve_file_system_uri(callback_id, args);
+	// DirectoryReader
+	if (!wcscmp(action, L"readEntries"))
+			return read_entries(callback_id, args);
+	// Entry
+	if (!wcscmp(action, L"getMetadata"))
+			return get_metadata(callback_id, args);
+	if (!wcscmp(action, L"moveTo"))
+			return move_to(callback_id, args);
+	if (!wcscmp(action, L"copyTo"))
+			return copy_to(callback_id, args);
+	if (!wcscmp(action, L"remove"))
+			return remove(callback_id, args);
+	if (!wcscmp(action, L"getParent"))
+			return get_parent(callback_id, args);
+	// FileEntry
+	if (!wcscmp(action, L"getFileMetadata"))
+			return get_file_metadata(callback_id, args);
+	// DirectoryEntry
+	if (!wcscmp(action, L"getDirectory"))
+			return get_directory(callback_id, args);
+	if (!wcscmp(action, L"removeRecursively"))
+			return remove_recursively(callback_id, args);
+	if (!wcscmp(action, L"getFile"))
+			return get_file(callback_id, args);
+	// FileReader
+	if (!wcscmp(action, L"readAsText"))
+			return read_as_text(callback_id, args);
+	if (!wcscmp(action, L"readAsDataURL"))
+			return read_as_data_url(callback_id, args);
+	// FileWriter
+	if (!wcscmp(action, L"write"))
+			return write(callback_id, args);
+	if (!wcscmp(action, L"truncate"))
+			return truncate(callback_id, args);
+
+	return DISP_E_MEMBERNOTFOUND;
+}
+
+static void file_module_init(void)
+{
+	int result;
+
+	// Initialize root paths
+	*temporary_root_path = 0;
+	*persistent_root_path = 0;
+
+	if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, persistent_root_path))) {
+		PathAppend(persistent_root_path, L"Cordova\\fs");
+		wcscpy_s(temporary_root_path, MAX_PATH, persistent_root_path);
+
+		temporary_dir = get_device_uuid();
+		PathAppend(temporary_root_path, temporary_dir);
+		PathAppend(persistent_root_path, persistent_dir);
+
+		result = SHCreateDirectory(NULL,temporary_root_path);
+		if(!SUCCEEDED(result) && (result != ERROR_FILE_EXISTS) && (result != ERROR_ALREADY_EXISTS))
+			*temporary_root_path = 0;
+
+		result = SHCreateDirectory(NULL,persistent_root_path);
+		if(!SUCCEEDED(result) && (result != ERROR_FILE_EXISTS) && (result != ERROR_ALREADY_EXISTS))
+			*persistent_root_path = 0;
+	}
+}
+
+static void file_module_close(void)
+{
+	int res;
+	SHFILEOPSTRUCT fileOp;
+
+	// Remove temporary filesystem (uuid based)
+	wcscpy_s(full_path, MAX_PATH, temporary_root_path);
+	full_path[wcslen(temporary_root_path) + 1] = 0; // double-null terminated required by SHFileOperation()
+	memset(&fileOp, 0, sizeof(SHFILEOPSTRUCT));
+	fileOp.wFunc = FO_DELETE;
+	fileOp.pFrom = full_path;
+	fileOp.fFlags = FOF_NO_UI | FOF_NOCONFIRMATION;
+
+	res = SHFileOperation(&fileOp);
+}
+
+DEFINE_CORDOVA_MODULE(File, L"File", file_module_exec, file_module_init, file_module_close)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/file.h
----------------------------------------------------------------------
diff --git a/Cordova/file.h b/Cordova/file.h
new file mode 100644
index 0000000..bdef226
--- /dev/null
+++ b/Cordova/file.h
@@ -0,0 +1,43 @@
+// Copyright 2012 Intel Corporation
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+// 
+//    http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <WTypes.h>
+
+#include "shell.h"
+
+typedef enum {
+	FILE_NO_ERR = 0,
+	NOT_FOUND_ERR,
+	SECURITY_ERR,
+	ABORT_ERR,
+	NOT_READABLE_ERR,
+	ENCODING_ERR,
+	NO_MODIFICATION_ALLOWED_ERR,
+	INVALID_STATE_ERR,
+	SYNTAX_ERR,
+	INVALID_MODIFICATION_ERR,
+	QUOTA_EXCEEDED_ERR,
+	TYPE_MISMATCH_ERR,
+	PATH_EXISTS_ERR
+} CordovaFsError;
+
+CordovaFsError path_from_uri(wchar_t *uri, wchar_t *path, DWORD *len, BOOL must_exist, BOOL *is_dir);
+wchar_t *make_entry(BOOL is_dir, wchar_t *root_path, wchar_t *rel_path);
+
+DECLARE_CORDOVA_MODULE(File)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/filetransfer.c
----------------------------------------------------------------------
diff --git a/Cordova/filetransfer.c b/Cordova/filetransfer.c
new file mode 100644
index 0000000..cd3cbb8
--- /dev/null
+++ b/Cordova/filetransfer.c
@@ -0,0 +1,486 @@
+// Copyright 2012 Intel Corporation
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+// 
+//    http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <Shlwapi.h>
+#include <WinInet.h>
+#include <stdio.h>
+
+#include "filetransfer.h"
+#include "common.h"
+#include "file.h"
+#include "json.h"
+
+#pragma comment(lib, "wininet.lib")
+
+
+#define CHUNK_SIZE (1024 * 1024) // 1 MB
+
+#define BOUNDARY "--------------------------cordova"
+
+#define _WIDE_CHAR(text) L##text
+#define WIDE_CHAR(text) _WIDE_CHAR(text)
+
+typedef enum {
+	TRANSFER_NO_ERR = 0,
+	FILE_NOT_FOUND_ERR,
+	INVALID_URL_ERR,
+	CONNECTION_ERR
+} FileTransferError;
+
+static void file_transfer_fail_callback(wchar_t *callback_id, wchar_t *src, wchar_t *target, DWORD http_status, FileTransferError err)
+{
+	const wchar_t *format = L"{code:%d,source:'%s',target:'%s',http_status:%d}";
+	wchar_t *error_text;
+
+	error_text = (wchar_t *) malloc(sizeof(wchar_t) * (1 + wcslen(format) + 2 + wcslen(src) + wcslen(target) + 5));
+	wsprintf(error_text, format, err, src, target, http_status);
+
+	cordova_fail_callback(callback_id, FALSE, CB_GENERIC_ERROR, error_text);
+
+	free(error_text);
+}
+
+static HRESULT download(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	JsonItem item;
+	CordovaFsError fs_err;
+	wchar_t *src_uri = NULL;
+	wchar_t *dst_uri = NULL;
+	HINTERNET inet = NULL;
+	HINTERNET file = NULL;
+	DWORD context = (DWORD) callback_id;
+	DWORD read;
+	HANDLE local_file = INVALID_HANDLE_VALUE;
+	wchar_t *entry;
+	DWORD index = 0;
+	DWORD status;
+	DWORD status_len = sizeof(status);
+	wchar_t full_path[MAX_PATH + 1];
+	DWORD full_path_size;
+	BYTE *buf = NULL;
+
+	// Validate array contents
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,		// 0- source uri
+											JSON_VALUE_STRING,				// 1- target path
+											JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+
+	// Get args
+	item = json_array_get_first(array);
+	src_uri = json_get_string_value(item);
+	item = json_array_get_next(item);
+	dst_uri = json_get_string_value(item);
+
+	// Check target path
+	full_path_size = MAX_PATH;
+	fs_err = path_from_uri(dst_uri, full_path, &full_path_size, FALSE, NULL);
+	if (fs_err != FILE_NO_ERR) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, FILE_NOT_FOUND_ERR);
+		goto out;
+	}
+
+	// Open source url
+	inet = InternetOpen(L"Cordova", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+	if (!inet) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+		goto out;
+	}
+
+	file = InternetOpenUrl(inet, src_uri, NULL, 0, 0, context);
+	if (!file) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, INVALID_URL_ERR);
+		goto out;
+	}
+
+	if (!HttpQueryInfo(file, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &status_len, &index)) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+		goto out;
+	}
+	if (status != 200) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, status, CONNECTION_ERR);
+		goto out;
+	}
+
+	// Create local file
+	local_file = CreateFile(full_path, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (local_file == INVALID_HANDLE_VALUE) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, FILE_NOT_FOUND_ERR);
+		goto out;
+	}
+
+	// Read data
+	buf = (BYTE *) malloc(CHUNK_SIZE);
+	read = 0;
+	while (InternetReadFile(file, buf, CHUNK_SIZE, &read)) {
+		DWORD written;
+
+		if (read == 0)
+			break;
+
+		if (!WriteFile(local_file, buf, read, &written, NULL)) {
+			file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, FILE_NOT_FOUND_ERR);
+			goto out;
+		}
+	}
+	if (GetLastError() != ERROR_SUCCESS) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+		goto out;
+	}
+
+	// Return entry
+	entry = make_entry(FALSE, full_path, NULL);
+	cordova_success_callback(callback_id, FALSE, entry);
+	free(entry);
+
+out:
+	json_free_args(array);
+	if (local_file != INVALID_HANDLE_VALUE)
+		CloseHandle(local_file);
+	if (file)
+		InternetCloseHandle(file);
+	if (inet)
+		InternetCloseHandle(inet);
+	if (src_uri)
+		free(src_uri);
+	if (dst_uri)
+		free(dst_uri);
+	if (buf)
+		free(buf);
+
+	return res;
+}
+
+static int get_internet_port(const wchar_t *uri)
+{
+	wchar_t inet_buf[INTERNET_MAX_PORT_NUMBER_LENGTH + 1];
+	DWORD size = INTERNET_MAX_PORT_NUMBER_LENGTH;
+	int res = INTERNET_DEFAULT_HTTP_PORT;
+
+	// Try to get explicit port number
+	if (UrlGetPart(uri, inet_buf, &size, URL_PART_PORT, 0) != S_OK) {
+		// Or default to scheme port 
+		if (UrlGetPart(uri, inet_buf, &size, URL_PART_SCHEME, 0) == S_OK) {
+			if (!wcscmp(inet_buf, L"https"))
+				res = INTERNET_DEFAULT_HTTPS_PORT;
+		}
+	} else
+		swscanf_s(inet_buf, L"%d", &res);
+
+	return res;
+}
+
+static const wchar_t *find_oject_name(const wchar_t *uri)
+{
+	wchar_t inet_buf[INTERNET_MAX_SCHEME_LENGTH + 1];
+	DWORD size = INTERNET_MAX_SCHEME_LENGTH;
+	unsigned int pos = 0;
+
+	if (UrlGetPart(uri, inet_buf, &size, URL_PART_SCHEME, 0) == S_OK)
+		pos += wcslen(inet_buf) + 3;
+
+	while (pos < wcslen(uri) && uri[pos] != L'/')
+		pos++;
+
+	return (uri + pos);
+}
+
+static HRESULT upload(BSTR callback_id, BSTR args)
+{
+	HRESULT res = S_OK;
+	JsonArray array;
+	JsonItem item;
+	JsonObjectItem param;
+	CordovaFsError fs_err;
+	wchar_t *item_val;
+	size_t item_len;
+	wchar_t *src_uri = NULL;
+	wchar_t *dst_uri = NULL;
+	wchar_t full_path[MAX_PATH + 1];
+	wchar_t server_name[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+	wchar_t user_name[INTERNET_MAX_USER_NAME_LENGTH + 1];
+	wchar_t passwd[INTERNET_MAX_PASSWORD_LENGTH + 1];
+	BOOL is_dir;
+	HINTERNET inet = NULL;
+	HINTERNET server = NULL;
+	HINTERNET req = NULL;
+	DWORD context = (DWORD) callback_id;
+	TextBuf txt_buf = NULL;
+	char *utf8_text = NULL;
+	int utf8_len;
+	DWORD written;
+	HANDLE file = INVALID_HANDLE_VALUE;
+	const char *end_contents = "\r\n--" BOUNDARY "--\r\n";
+	ULARGE_INTEGER file_size;
+	DWORD index = 0;
+	DWORD status;
+	DWORD status_len = sizeof(status);
+	DWORD size;
+	BYTE *buf = NULL;
+
+	// Validate array contents
+	if (!json_parse_and_validate_args(args, &array, JSON_VALUE_STRING,			// 0- file path
+											JSON_VALUE_STRING,					// 1- server
+											JSON_VALUE_STRING | JSON_VALUE_NULL,// 2- file key
+											JSON_VALUE_STRING | JSON_VALUE_NULL,// 3- file name
+											JSON_VALUE_STRING | JSON_VALUE_NULL,// 4- mime type
+											JSON_VALUE_OBJECT | JSON_VALUE_NULL,// 5- params (key/value pairs)
+											JSON_VALUE_BOOL | JSON_VALUE_NULL,	// 6- trust all hosts
+											JSON_VALUE_BOOL | JSON_VALUE_NULL,	// 7- chunkedMode
+											JSON_VALUE_INVALID)) {
+		res = E_FAIL;
+		goto out;
+	}
+
+	// Get source & target uri
+	item = json_array_get_first(array);
+	src_uri = json_get_string_value(item);
+	item = json_array_get_next(item);
+	dst_uri = json_get_string_value(item);
+
+	// Check source path
+	size = MAX_PATH;
+	fs_err = path_from_uri(src_uri, full_path, &size, TRUE, &is_dir);
+	if (fs_err != FILE_NO_ERR || is_dir) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, FILE_NOT_FOUND_ERR);
+		goto out;
+	}
+
+	file = CreateFile(full_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (file == INVALID_HANDLE_VALUE) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+		goto out;
+	}
+
+	file_size.LowPart = GetFileSize(file, &file_size.HighPart);
+
+	// Connect to server
+	inet = InternetOpen(L"Cordova", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+	if (!inet) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+		goto out;
+	}
+
+	size = INTERNET_MAX_HOST_NAME_LENGTH;
+	UrlGetPart(dst_uri, server_name, &size, URL_PART_HOSTNAME, 0);
+	size = INTERNET_MAX_USER_NAME_LENGTH;
+	UrlGetPart(dst_uri, user_name, &size, URL_PART_USERNAME, 0);
+	size = INTERNET_MAX_PASSWORD_LENGTH;
+	UrlGetPart(dst_uri, passwd, &size, URL_PART_PASSWORD, 0);
+	server = InternetConnect(inet, server_name, get_internet_port(dst_uri), user_name, passwd, INTERNET_SERVICE_HTTP, 0, 0);
+	if (!server) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, INVALID_URL_ERR);
+		goto out;
+	}
+
+	// Build send request
+	req = HttpOpenRequest(server, L"POST", find_oject_name(dst_uri), NULL, NULL, NULL, 0, context);
+	if (!req) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, INVALID_URL_ERR);
+		goto out;
+	}
+
+	// 1- Headers
+	buf = (BYTE *) malloc(CHUNK_SIZE);
+	txt_buf = text_buf_new();
+
+	text_buf_append(txt_buf, L"Content-Type: multipart/form-data; boundary=" WIDE_CHAR(BOUNDARY));
+	if (!HttpAddRequestHeaders(req, text_buf_get(txt_buf), text_buf_get_len(txt_buf), HTTP_ADDREQ_FLAG_ADD)) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+		goto end_req;
+	}
+
+	item = json_array_item_at(array, 5);
+	if (json_get_value_type(item) != JSON_VALUE_NULL) {
+		param = json_get_object_value(item);
+		while (param && json_get_value_type(to_item(param)) != JSON_VALUE_EMPTY) {
+			wchar_t *tag;
+
+			tag = json_object_get_prop_id(param);
+			item_val = json_get_string_value(to_item(param));
+
+			text_buf_reset(txt_buf);
+			text_buf_append_len(txt_buf, tag, wcslen(tag)); 
+			text_buf_append(txt_buf, L":\"");
+			text_buf_append_len(txt_buf, item_val, wcslen(item_val)); 
+			text_buf_append(txt_buf, L"\"");
+
+			free(tag);
+			free(item_val);
+
+			if (!HttpAddRequestHeaders(req, text_buf_get(txt_buf), text_buf_get_len(txt_buf), HTTP_ADDREQ_FLAG_ADD)) {
+				file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+				goto out;
+			}
+
+			param = json_object_get_next(param);
+		}
+	}
+
+	// 2- Contents
+	// 2.1 Contents headers
+	text_buf_reset(txt_buf);
+	text_buf_append(txt_buf, L"--" WIDE_CHAR(BOUNDARY) L"\r\nContent-Disposition: form-data; name=\"");
+
+	item = json_array_item_at(array, 2);
+	if (json_get_value_type(item) == JSON_VALUE_NULL)
+		item_val = _wcsdup(L"uploaded_name");
+	else
+		item_val = json_get_string_value(item);
+	item_len = wcslen(item_val);
+	text_buf_append_len(txt_buf, item_val, item_len); 
+	text_buf_append(txt_buf, L"\"; filename=\"");
+	free(item_val);
+
+	item = json_array_item_at(array, 3);
+	if (json_get_value_type(item) == JSON_VALUE_NULL)
+		item_val = _wcsdup(L"uploaded_file");
+	else
+		item_val = json_get_string_value(item);
+	item_len = wcslen(item_val);
+	text_buf_append_len(txt_buf, item_val, item_len); 
+	text_buf_append(txt_buf, L"\"\r\nContent-Type: ");
+	free(item_val);
+
+	item = json_array_item_at(array, 4);
+	if (json_get_value_type(item) == JSON_VALUE_NULL)
+		item_val = _wcsdup(L"application/octet-stream");
+	else
+		item_val = json_get_string_value(item);
+	item_len = wcslen(item_val);
+	text_buf_append_len(txt_buf, item_val, item_len); 
+	text_buf_append(txt_buf, L"\r\n\r\n");
+	free(item_val);
+
+	utf8_len = WideCharToMultiByte(CP_UTF8, 0, text_buf_get(txt_buf), text_buf_get_len(txt_buf), NULL, 0, NULL, NULL); // First call to get length
+	utf8_text = (char *) malloc(utf8_len + 1);
+	if (!WideCharToMultiByte(CP_UTF8, 0, text_buf_get(txt_buf), text_buf_get_len(txt_buf), utf8_text, utf8_len, NULL, NULL)) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+		goto end_req;
+	}
+
+	wsprintf((wchar_t *) buf, L"Content-Length: %I64d", file_size.QuadPart + utf8_len + strlen(end_contents));
+	if (!HttpAddRequestHeaders(req, (wchar_t *) buf, wcslen((wchar_t *) buf), HTTP_ADDREQ_FLAG_ADD)) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+		goto end_req;
+	}
+
+	if (!HttpSendRequestEx(req, NULL, NULL, 0, context)) {
+			file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+			goto end_req;
+	}
+
+	if (!InternetWriteFile(req, utf8_text, utf8_len, &written)) {
+			file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+			goto end_req;
+	}
+
+	// 2.2 Contents data
+	do {
+		if (!ReadFile(file, buf, CHUNK_SIZE, &size, NULL)) {
+			file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+			goto out;
+		}
+
+		if (size == 0)
+			break;
+
+		if (!InternetWriteFile(req, buf, size, &written)) {
+			file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+			goto end_req;
+		}
+	} while (TRUE);
+
+	// 2.3 Contents footer
+	if (!InternetWriteFile(req, end_contents, strlen(end_contents), &written)) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+		goto end_req;
+	}
+
+end_req:
+
+	// Close request
+	if (!HttpEndRequest(req, NULL, 0, 0)) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+		goto out;
+	}
+
+	if (!HttpQueryInfo(req, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &status_len, &index)) {
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, 0, CONNECTION_ERR);
+		goto out;
+	}
+
+	if (status != 200) { // Either failure
+		file_transfer_fail_callback(callback_id, src_uri, dst_uri, status, CONNECTION_ERR);
+		goto out;
+	} else { // Or success
+		text_buf_reset(txt_buf);
+		text_buf_append(txt_buf, L"{responseCode:200,response:'");
+		((wchar_t *) buf)[0] = 0;
+		InternetReadFile(req, buf, CHUNK_SIZE - 1, &size);
+		((wchar_t *) buf)[size] = 0;
+		text_buf_append(txt_buf, (wchar_t *) buf);
+		text_buf_append(txt_buf, L"',bytesSent:");
+		wsprintf((wchar_t *) buf, L"%I64d", file_size.QuadPart);
+		text_buf_append(txt_buf, (wchar_t *) buf);
+		text_buf_append(txt_buf, L"}");
+
+		cordova_success_callback(callback_id, FALSE, text_buf_get(txt_buf));
+	}
+
+out:
+	json_free_args(array);
+	if (req)
+		InternetCloseHandle(req);
+	if (server)
+		InternetCloseHandle(server);
+	if (inet)
+		InternetCloseHandle(inet);
+	if (src_uri)
+		free(src_uri);
+	if (dst_uri)
+		free(dst_uri);
+	if (buf)
+		free(buf);
+	if (txt_buf)
+		text_buf_free(txt_buf);
+	if (utf8_text)
+		free(utf8_text);
+	if (file != INVALID_HANDLE_VALUE)
+		CloseHandle(file);
+
+	return res;
+}
+
+HRESULT file_transfer_exec(BSTR callback_id, BSTR action, BSTR args, VARIANT *result)
+{
+	if (!wcscmp(action, L"download"))
+			return download(callback_id, args);
+	if (!wcscmp(action, L"upload"))
+			return upload(callback_id, args);
+
+	return DISP_E_MEMBERNOTFOUND;
+}
+
+DEFINE_CORDOVA_MODULE(FileTransfer, L"FileTransfer", file_transfer_exec, NULL, NULL)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/filetransfer.h
----------------------------------------------------------------------
diff --git a/Cordova/filetransfer.h b/Cordova/filetransfer.h
new file mode 100644
index 0000000..c331ad6
--- /dev/null
+++ b/Cordova/filetransfer.h
@@ -0,0 +1,22 @@
+// Copyright 2012 Intel Corporation
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+// 
+//    http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "shell.h"
+
+DECLARE_CORDOVA_MODULE(FileTransfer)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/7807de07/Cordova/json.c
----------------------------------------------------------------------
diff --git a/Cordova/json.c b/Cordova/json.c
new file mode 100644
index 0000000..b99ba07
--- /dev/null
+++ b/Cordova/json.c
@@ -0,0 +1,545 @@
+// Copyright 2012 Intel Corporation
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <wchar.h>
+#include <assert.h>
+
+#include "json.h"
+
+#define JSON_TRUE	L"true"
+#define JSON_FALSE	L"false"
+#define JSON_NULL	L"null"
+
+struct _JsonItem {
+	// Common fields
+	JsonValueType value_type;
+	union {
+		wchar_t *as_string;
+		int as_int;
+		INT64 as_int64;
+		double as_double;
+		BOOL as_bool;
+		JsonArray as_array;
+		JsonObject as_object;
+	} value;
+	size_t value_as_string_len;
+	struct _JsonItem *next;
+};
+
+struct _JsonObjectItem {
+	// Common fields
+	JsonValueType value_type;
+	union {
+		wchar_t *as_string;
+		int as_int;
+		double as_double;
+		JsonArray as_array;
+		JsonObject as_object;
+	} value;
+	size_t value_as_string_len;
+	struct _JsonItem *next;
+	// Specific fields
+	wchar_t *tag;
+	size_t tag_len;
+};
+
+struct _JsonCursor {
+	wchar_t *buf;
+	size_t max;
+	size_t pos;
+};
+typedef struct _JsonCursor JsonCursor;
+
+static BOOL json_parse_array(JsonCursor *cursor, JsonArray array);
+static BOOL json_parse_object(JsonCursor *cursor, JsonObject object);
+
+static void json_init_cursor(wchar_t * buf, JsonCursor *cursor)
+{
+	memset((void *)cursor, 0, sizeof(JsonCursor));
+	cursor->buf = buf;
+	cursor->max = wcslen(buf);
+}
+
+static BOOL json_parse_string(JsonCursor *cursor, JsonItem item)
+{
+	wchar_t *buf = cursor->buf;
+	BOOL escape;
+
+	cursor->pos++; // Initial '"'
+	item->value.as_string = buf + cursor->pos;
+	while (cursor->pos < cursor->max) {
+		if (buf[cursor->pos] == '"' && !escape) {
+			cursor->pos++; // Trailing '"'
+			break;
+		}
+
+		if (buf[cursor->pos] == '\\' && !escape)
+			escape = TRUE;
+		else
+			escape = FALSE;
+
+		cursor->pos++;
+		item->value_as_string_len++;
+	}
+
+	return (cursor->pos == cursor->max) ? FALSE : TRUE;
+}
+
+static BOOL json_parse_number(JsonCursor *cursor, JsonItem item)
+{
+	wchar_t *buf = cursor->buf;
+	wchar_t *value = buf + cursor->pos;
+	size_t value_len = 0;
+	BOOL has_dot = (buf[cursor->pos] == '.') ? TRUE : FALSE;
+	INT64 val64;
+
+	cursor->pos++;
+	value_len++;
+	while (cursor->pos < cursor->max) {
+		if (buf[cursor->pos] == '.') {
+			if (has_dot)
+				return FALSE;
+			else
+				has_dot = TRUE;
+		} else if (!iswdigit(buf[cursor->pos]))
+			break;
+
+		cursor->pos++;
+		value_len++;
+	}
+
+	if (cursor->pos == cursor->max)
+		return FALSE;
+
+	item->value_type = (has_dot) ? JSON_VALUE_DOUBLE : JSON_VALUE_INT;
+	if (item->value_type == JSON_VALUE_INT) {
+		if (_snwscanf_s(value, value_len, L"%I64d", &val64) != 1)
+			return FALSE;
+		if (val64 > MAXINT) {
+			item->value.as_int64 = val64;
+			item->value_type = JSON_VALUE_INT64;
+		} else
+			item->value.as_int = (int) val64;
+			item->value.as_int64 = val64;
+	} else {
+		if (_snwscanf_s(value, value_len, L"%f", &item->value.as_double) != 1)
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+static BOOL json_parse_value(JsonCursor *cursor, JsonItem item)
+{
+	wchar_t *buf = cursor->buf;
+
+	if (buf[cursor->pos] == '\"') {
+		item->value_type = JSON_VALUE_STRING;
+		return json_parse_string(cursor, item);
+	} else if (iswdigit(buf[cursor->pos]) || buf[cursor->pos] == '-' || buf[cursor->pos] == '.') {
+		return json_parse_number(cursor, item);
+	} else if (buf[cursor->pos] == '[') {
+		item->value_type = JSON_VALUE_ARRAY;
+		item->value.as_array = (JsonArray) calloc(1, sizeof(struct _JsonItem));
+		return json_parse_array(cursor, item->value.as_array);
+	}  else if (buf[cursor->pos] == '{') {
+		item->value_type = JSON_VALUE_OBJECT;
+		item->value.as_object = (JsonObject) calloc(1, sizeof(struct _JsonObjectItem));
+		return json_parse_object(cursor, item->value.as_object);
+	} else if ((cursor->pos + wcslen(JSON_TRUE)) < cursor->max && !wcsncmp(buf + cursor->pos, JSON_TRUE, wcslen(JSON_TRUE))) {
+		item->value_type = JSON_VALUE_BOOL;
+		item->value.as_bool = TRUE;
+		cursor->pos += wcslen(JSON_TRUE);
+		return TRUE;
+	} else if ((cursor->pos + wcslen(JSON_FALSE)) < cursor->max && !wcsncmp(buf + cursor->pos, JSON_FALSE, wcslen(JSON_FALSE))) {
+		item->value_type = JSON_VALUE_BOOL;
+		item->value.as_bool = FALSE;
+		cursor->pos += wcslen(JSON_FALSE);
+		return TRUE;
+	} else if ((cursor->pos + wcslen(JSON_NULL)) < cursor->max && !wcsncmp(buf + cursor->pos, JSON_NULL, wcslen(JSON_NULL))) {
+		item->value_type = JSON_VALUE_NULL;
+		item->value.as_string = buf + cursor->pos;
+		item->value_as_string_len = wcslen(JSON_NULL);
+		cursor->pos += item->value_as_string_len;
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static BOOL json_parse_object(JsonCursor *cursor, JsonObject object)
+{
+	wchar_t *buf = cursor->buf;
+	struct _JsonObjectItem *item = (struct _JsonObjectItem *) object;
+
+	cursor->pos++;
+	if (buf[cursor->pos] == '}') {
+		cursor->pos++;
+		item->value_type = JSON_VALUE_EMPTY;
+		return TRUE;
+	}
+
+	while (cursor->pos < cursor->max) {
+		if (buf[cursor->pos] != '\"')
+			return FALSE;
+
+		// Tag
+		cursor->pos++;
+		item->tag = buf + cursor->pos;
+		while (cursor->pos < cursor->max && buf[cursor->pos] != '\"') {
+			cursor->pos++;
+			item->tag_len++;
+		}
+		if (cursor->pos == cursor->max)
+			return FALSE;
+
+		// Seprator
+		cursor->pos++;
+		if (buf[cursor->pos] != ':')
+			return FALSE;
+
+		// Value
+		cursor->pos++;
+		if(!json_parse_value(cursor, (JsonItem) item))
+			return FALSE;
+
+		// Next
+		if (buf[cursor->pos] == '}') {
+			cursor->pos++;
+			break;
+		}
+		if (buf[cursor->pos] != ',')
+			return FALSE;
+
+		cursor->pos++;
+		item->next = (JsonItem) calloc(1, sizeof(struct _JsonObjectItem));
+		item = (JsonObjectItem) item->next;
+	}
+
+	return TRUE;
+}
+
+static BOOL json_parse_array(JsonCursor *cursor, JsonArray item)
+{
+	wchar_t *buf = cursor->buf;
+
+	if (buf[cursor->pos] != '[')
+		return FALSE;
+
+	cursor->pos++;
+	if (buf[cursor->pos] == ']') {
+		cursor->pos++;
+		item->value_type = JSON_VALUE_EMPTY;
+		return TRUE;
+	}
+
+	while (cursor->pos < cursor->max) {
+		if (!json_parse_value(cursor, (JsonItem) item))
+			return FALSE;
+
+		// Next
+		if (buf[cursor->pos] == ']') {
+			cursor->pos++;
+			break;
+		}
+		if (buf[cursor->pos] != ',')
+			return FALSE;
+
+		cursor->pos++;
+		item->next = (JsonItem) calloc(1, sizeof(struct _JsonItem));
+		item = (JsonItem) item->next;
+	}
+
+	return TRUE;
+}
+
+BOOL json_parse_args(wchar_t * buf, JsonArray *item)
+{
+	JsonCursor cursor;
+	BOOL success;
+
+	json_init_cursor(buf, &cursor);
+
+	*item = (JsonArray) calloc(1, sizeof(struct _JsonItem));
+	success = json_parse_array(&cursor, *item);
+	if (success && cursor.pos == cursor.max)
+		return TRUE;
+
+	return FALSE;
+}
+
+static void json_free_item(JsonItem item)
+{
+	JsonItem current;
+
+	while (item != NULL) {
+		current = item;
+		switch (item->value_type) {
+		case JSON_VALUE_ARRAY:
+			json_free_item((JsonItem) current->value.as_array);
+			break;
+		case JSON_VALUE_OBJECT:
+			json_free_item((JsonItem) current->value.as_object);
+			break;
+		default:
+			break;
+		}
+
+		item = item->next;
+		free(current);
+	}
+}
+
+void json_free_args(JsonArray item)
+{
+	json_free_item((JsonItem) item);
+}
+
+JsonItem json_array_get_next(JsonItem item)
+{
+	return item->next;
+}
+
+JsonValueType json_get_value_type(JsonItem item)
+{
+	return item->value_type;
+}
+
+int json_get_int_value(JsonItem item)
+{
+	return item->value.as_int;
+}
+
+INT64 json_get_int64_value(JsonItem item)
+{
+	return item->value.as_int64;
+}
+
+BOOL json_get_bool_value(JsonItem item)
+{
+	return item->value.as_bool;
+}
+
+double json_get_double_value(JsonItem item)
+{
+	return item->value.as_double;
+}
+
+static wchar_t decode_unicode_char(const wchar_t *text)
+{
+	wchar_t val = 0;
+	int i;
+	const BYTE *buf = (const BYTE *) text;
+
+	for(i = 1; i <= 4; i++) {
+		BYTE c = buf[i];
+		val <<= 4;
+		if(isdigit(c))
+			val += c - '0';
+		else if(c >= 'a' && c <= 'f')
+			val += c - 'a' + 10;
+		else if(c >= 'A' && c <= 'F')
+			val += c - 'A' + 10;
+		else
+			return 0;
+	}
+
+	return val;
+}
+
+wchar_t *json_get_string_value(JsonItem item)
+{
+	size_t src_index = 0;
+	size_t val_index = 0;
+	const wchar_t *text = item->value.as_string;
+
+	wchar_t *val = (wchar_t*) malloc(sizeof(wchar_t) * (item->value_as_string_len + 1));
+
+	while (src_index < item->value_as_string_len) {
+		if (text[src_index] == '\\') {
+			src_index++;
+			if (src_index == item->value_as_string_len)
+				break;
+
+			switch(text[src_index]) {
+			case 'u':
+				if ((item->value_as_string_len - src_index) > 3) {
+					wchar_t unicode_val = decode_unicode_char(text + src_index);
+					if (val) {
+						val[val_index] = unicode_val;
+						src_index += 3;
+					} else
+						val[val_index] = text[src_index];
+				} else
+					val[val_index] = text[src_index];
+				break;
+			case '"':
+			case '\\':
+			case '/':
+				val[val_index] = text[src_index];
+				break;
+			case 'b':
+				val[val_index] = '\b';
+				break;
+			case 'f':
+				val[val_index] = '\f';
+				break;
+			case 'n':
+				val[val_index] = '\n';
+				break;
+			case 'r':
+				val[val_index] = '\r';
+				break;
+			case 't':
+				val[val_index] = '\t';
+				break;
+			default:
+				val[val_index] = text[src_index];
+			}
+
+			val_index++;
+			src_index++;
+		} else
+			val[val_index++] = text[src_index++];
+	}
+
+	val[val_index] = 0;
+
+	return val;
+}
+
+JsonObject json_get_object_value(JsonItem item)
+{
+	return item->value.as_object;
+}
+
+JsonArray json_get_array_value(JsonItem item)
+{
+	return item->value.as_array;
+}
+
+static int json_container_item_count(JsonItem item)
+{
+	int count = 0;
+
+	while (item != NULL) {
+		item = item->next;
+		count++;
+	}
+
+	return count;
+}
+
+static JsonItem json_container_item_at(JsonItem item, int position)
+{
+	while (item != NULL && position) {
+		item = item->next;
+		position--;
+	}
+
+	return item;
+}
+
+int json_array_item_count(JsonArray array)
+{
+	return json_container_item_count((JsonItem) array);
+}
+
+JsonItem json_array_item_at(JsonArray array, int position)
+{
+	return json_container_item_at((JsonItem) array, position);
+}
+
+static BOOL is_type_compatible(JsonValueType current, JsonValueType expected)
+{
+	if (expected & JSON_VALUE_INT64)
+		return ((expected & current) || (JSON_VALUE_INT & current));
+
+	return (expected & current);
+}
+
+static BOOL internal_json_array_validate_contents(JsonArray array, JsonValueType type, va_list args)
+{
+	while(type != JSON_VALUE_INVALID) {
+		if (!array)
+			return FALSE;
+		if (!is_type_compatible(array->value_type, type))
+			return FALSE;
+
+		array = array->next;
+		type = va_arg(args, JsonValueType);
+	}
+	
+	return TRUE;
+}
+
+BOOL json_array_validate_contents(JsonArray array, JsonValueType type, ...)
+{
+	va_list args;
+
+	va_start(args, type);
+	return internal_json_array_validate_contents(array, type, args);
+}
+
+BOOL json_parse_and_validate_args(wchar_t * buf, JsonArray *array, JsonValueType type, ...)
+{
+	va_list args;
+
+	if (!json_parse_args(buf, array))
+		return FALSE;
+
+	va_start(args, type);
+	return internal_json_array_validate_contents(*array, type, args);
+}
+
+int json_object_prop_count(JsonObject object)
+{
+	return json_container_item_count((JsonItem) object);
+}
+
+JsonObjectItem json_object_prop_at(JsonObject object, int position)
+{
+	return (JsonObjectItem) json_container_item_at((JsonItem) object, position);
+}
+
+JsonObjectItem json_object_find_prop(JsonObject object, const wchar_t *id, JsonValueType type)
+{
+	while (object != NULL) {
+		if (!wcsncmp(id, (wchar_t *) object->tag, wcslen(id)) &&
+			wcslen(id) == object->tag_len && is_type_compatible(object->value_type, type))
+				return (JsonObjectItem) object;
+		object = (struct _JsonObjectItem *) object->next;
+	}
+
+	return NULL;
+}
+
+wchar_t *json_object_get_prop_id(JsonObject object)
+{
+	wchar_t *id = (wchar_t*) malloc(sizeof(wchar_t) * (object->tag_len + 1));
+
+	wcsncpy_s(id, object->tag_len + 1, object->tag, object->tag_len);
+
+	return id;
+}
+
+JsonObjectItem json_object_get_next(JsonObjectItem item)
+{
+	return (JsonObjectItem) item->next;
+}


Mime
View raw message