Implement memory-mapped zip files in ijar for Windows.

Progress towards #276.

--
MOS_MIGRATED_REVID=114829911
diff --git a/third_party/ijar/BUILD b/third_party/ijar/BUILD
index 0f4390b..edd6bf1 100644
--- a/third_party/ijar/BUILD
+++ b/third_party/ijar/BUILD
@@ -16,9 +16,15 @@
 cc_library(
     name = "zip",
     srcs = [
-        "mapped_file_unix.cc",
         "zip.cc",
-    ],
+    ] + select({
+        "//src:windows": [
+            "mapped_file_windows.cc",
+        ],
+        "//conditions:default": [
+            "mapped_file_unix.cc",
+        ],
+    }),
     hdrs = [
         "common.h",
         "mapped_file.h",
diff --git a/third_party/ijar/mapped_file_windows.cc b/third_party/ijar/mapped_file_windows.cc
new file mode 100644
index 0000000..6b4ba30
--- /dev/null
+++ b/third_party/ijar/mapped_file_windows.cc
@@ -0,0 +1,203 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed 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 <stdio.h>
+#include <windows.h>
+#include <sys/cygwin.h>
+
+#include "third_party/ijar/mapped_file.h"
+
+#define MAX_ERROR 2048
+
+namespace devtools_ijar {
+
+static char errmsg[MAX_ERROR] = "";
+
+void PrintLastError(const char* op) {
+  char *message;
+  DWORD err = GetLastError();
+  FormatMessage(
+      FORMAT_MESSAGE_ALLOCATE_BUFFER
+          | FORMAT_MESSAGE_FROM_SYSTEM
+          | FORMAT_MESSAGE_IGNORE_INSERTS,
+      NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+      reinterpret_cast<char *>(&message),
+      0, NULL);
+  snprintf(errmsg, MAX_ERROR, "%s: %s", op, message);
+  LocalFree(message);
+}
+
+struct MappedInputFileImpl {
+  HANDLE file_;
+  HANDLE mapping_;
+
+  MappedInputFileImpl(HANDLE file, HANDLE mapping) {
+    file_ = file;
+    mapping_ = mapping;
+  }
+};
+
+MappedInputFile::MappedInputFile(const char* name) {
+  impl_ = NULL;
+  opened_ = false;
+  errmsg_ = errmsg;
+
+  char* path = reinterpret_cast<char*>(
+      cygwin_create_path(CCP_POSIX_TO_WIN_A, name));
+  HANDLE file = CreateFile(
+      path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+  free(path);
+  if (file == INVALID_HANDLE_VALUE) {
+    PrintLastError("CreateFile()");
+    return;
+  }
+
+  LARGE_INTEGER size;
+  if (!GetFileSizeEx(file, &size)) {
+    PrintLastError("GetFileSizeEx()");
+    CloseHandle(file);
+    return;
+  }
+
+  HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY,
+      size.HighPart, size.LowPart, NULL);
+  if (mapping == NULL) {
+    PrintLastError("CreateFileMapping()");
+    CloseHandle(file);
+    return;
+  }
+
+  void *view = MapViewOfFileEx(mapping, FILE_MAP_READ, 0, 0, 0, NULL);
+  if (view == NULL) {
+    PrintLastError("MapViewOfFileEx()");
+    CloseHandle(mapping);
+    CloseHandle(file);
+    return;
+  }
+
+  impl_ = new MappedInputFileImpl(file, mapping);
+  length_ = size.QuadPart;
+  buffer_ = reinterpret_cast<u1*>(view);
+  opened_ = true;
+}
+
+MappedInputFile::~MappedInputFile() {
+  delete impl_;
+}
+
+void MappedInputFile::Discard(size_t bytes) {
+  // This is not supported on Windows for now. I'm not sure if we can unmap
+  // parts of an existing view and that this is necessary for Windows at all.
+  // At any rate, this only matters for >2GB (or maybe >4GB?) input files.
+}
+
+int MappedInputFile::Close() {
+  if (!UnmapViewOfFile(buffer_)) {
+    PrintLastError("UnmapViewOfFile()");
+    return -1;
+  }
+
+  if (!CloseHandle(impl_->mapping_)) {
+    PrintLastError("CloseHandle(mapping)");
+    return -1;
+  }
+
+  if (!CloseHandle(impl_->file_)) {
+    PrintLastError("CloseHandle(file)");
+    return -1;
+  }
+
+  return 0;
+}
+
+struct MappedOutputFileImpl {
+  HANDLE file_;
+  HANDLE mapping_;
+
+  MappedOutputFileImpl(HANDLE file, HANDLE mapping) {
+    file_ = file;
+    mapping_ = mapping;
+  }
+};
+
+MappedOutputFile::MappedOutputFile(const char* name, u8 estimated_size) {
+  impl_ = NULL;
+  opened_ = false;
+  errmsg_ = errmsg;
+
+  char* path = reinterpret_cast<char*>(
+      cygwin_create_path(CCP_POSIX_TO_WIN_A, name));
+  HANDLE file = CreateFile(
+      path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+  free(path);
+  if (file == INVALID_HANDLE_VALUE) {
+    PrintLastError("CreateFile()");
+    return;
+  }
+
+  HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READWRITE,
+      estimated_size >> 32, estimated_size & 0xffffffffUL, NULL);
+  if (mapping == NULL) {
+    PrintLastError("CreateFileMapping()");
+    CloseHandle(file);
+    return;
+  }
+
+  void *view = MapViewOfFileEx(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
+  if (view == NULL) {
+    PrintLastError("MapViewOfFileEx()");
+    CloseHandle(mapping);
+    CloseHandle(file);
+    return;
+  }
+
+  impl_ = new MappedOutputFileImpl(file, mapping);
+  buffer_ = reinterpret_cast<u1*>(view);
+  opened_ = true;
+}
+
+MappedOutputFile::~MappedOutputFile() {
+  delete impl_;
+}
+
+int MappedOutputFile::Close(int size) {
+  if (!UnmapViewOfFile(buffer_)) {
+    PrintLastError("UnmapViewOfFile()");
+    return -1;
+  }
+
+  if (!CloseHandle(impl_->mapping_)) {
+    PrintLastError("CloseHandle(mapping)");
+    return -1;
+  }
+
+  if (!SetFilePointer(impl_->file_, size, NULL, FILE_BEGIN)) {
+    PrintLastError("SetFilePointer()");
+    return -1;
+  }
+
+  if (!SetEndOfFile(impl_->file_)) {
+    PrintLastError("SetEndOfFile()");
+    return -1;
+  }
+
+  if (!CloseHandle(impl_->file_)) {
+    PrintLastError("CloseHandle(file)");
+    return -1;
+  }
+
+  return 0;
+}
+
+}  // namespace devtools_ijar