Enforce a line limit of 50,000 for pretty file formatting.

Files with large number of lines are treated as raw.

Change-Id: Id793e6b09033c8c625cb1004c937f5a46fbc7a93
diff --git a/java/com/google/gitiles/BlobSoyData.java b/java/com/google/gitiles/BlobSoyData.java
index c505ed4..f1710d1 100644
--- a/java/com/google/gitiles/BlobSoyData.java
+++ b/java/com/google/gitiles/BlobSoyData.java
@@ -49,6 +49,13 @@
    */
   private static final int MAX_FILE_SIZE = 10 << 20;
 
+  /**
+   * Maximum number of lines to be displayed. Files larger than this will be displayed as binary
+   * files, even on a text content. For example really big XML files may be above this limit and
+   * will get displayed as binary.
+   */
+  private static final int MAX_LINE_COUNT = 50000;
+
   private final GitilesView view;
   private final ObjectReader reader;
 
@@ -71,6 +78,9 @@
     try {
       byte[] raw = loader.getCachedBytes(MAX_FILE_SIZE);
       content = !RawText.isBinary(raw) ? RawParseUtils.decode(raw) : null;
+      if (isContentTooLargeForDisplay(content)) {
+        content = null;
+      }
     } catch (LargeObjectException.OutOfMemory e) {
       throw e;
     } catch (LargeObjectException e) {
@@ -188,4 +198,21 @@
       return ext;
     }
   }
+
+  private static boolean isContentTooLargeForDisplay(String content) {
+    if (content == null) {
+      return false;
+    }
+
+    int lines = 0;
+    int nl = -1;
+    while (true) {
+      nl = nextLineBreak(content, nl + 1, content.length());
+      if (nl < 0) {
+        return false;
+      } else if (++lines == MAX_LINE_COUNT) {
+        return true;
+      }
+    }
+  }
 }
diff --git a/javatests/com/google/gitiles/PathServletTest.java b/javatests/com/google/gitiles/PathServletTest.java
index c0f98b1..c8ab575 100644
--- a/javatests/com/google/gitiles/PathServletTest.java
+++ b/javatests/com/google/gitiles/PathServletTest.java
@@ -102,6 +102,34 @@
   }
 
   @Test
+  public void fileWithMaxLines() throws Exception {
+    int MAX_LINE_COUNT = 50000;
+    StringBuilder contentBuilder = new StringBuilder();
+    for (int i = 1; i < MAX_LINE_COUNT; i++) {
+      contentBuilder.append("\n");
+    }
+    repo.branch("master").commit().add("bar", contentBuilder.toString()).create();
+
+    Map<String, ?> data = buildData("/repo/+/master/bar");
+    SoyListData lines = (SoyListData) getBlobData(data).get("lines");
+    assertThat(lines.length()).isEqualTo(MAX_LINE_COUNT - 1);
+  }
+
+  @Test
+  public void fileLargerThanSupportedLines() throws Exception {
+    int MAX_LINE_COUNT = 50000;
+    StringBuilder contentBuilder = new StringBuilder();
+    for (int i = 1; i <= MAX_LINE_COUNT; i++) {
+      contentBuilder.append("\n");
+    }
+    repo.branch("master").commit().add("largebar", contentBuilder.toString()).create();
+
+    Map<String, ?> data = buildData("/repo/+/master/largebar");
+    SoyListData lines = (SoyListData) getBlobData(data).get("lines");
+    assertThat(lines).isNull();
+  }
+
+  @Test
   public void symlinkHtml() throws Exception {
     final RevBlob link = repo.blob("foo");
     repo.branch("master")