/* * Copyright 2000-2016 JetBrains s.r.o. * * 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. */ package com.intellij.openapi.diff.impl.patch; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.FileStatus; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ListIterator; import java.util.regex.Matcher; import java.util.regex.Pattern; public class BinaryPatchContentParser { @NonNls private static final Pattern ourGitBinaryLineSize = Pattern.compile("literal\\s+(\\d+)\\s*"); public static FilePatch readGitBinaryFormatPatch(@NotNull ListIterator<String> iterator, @NotNull FileStatus parsedStatus) throws PatchSyntaxException { ByteArrayOutputStream afterStream = new ByteArrayOutputStream(); ByteArrayOutputStream beforeStream = new ByteArrayOutputStream(); checkNotEOF(iterator); try { String next = iterator.next(); Matcher literalMatcher = ourGitBinaryLineSize.matcher(next); if (literalMatcher.matches()) { getContent(iterator, afterStream, literalMatcher.group(1)); } //parse literal before content if exist if (iterator.hasNext() && parsedStatus != FileStatus.ADDED) { next = iterator.next(); if (StringUtil.isEmptyOrSpaces(next) && iterator.hasNext()) { next = iterator.next(); } if (literalMatcher.reset(next).matches()) { getContent(iterator, beforeStream, literalMatcher.group(1)); } else { // does not contain 'before' literal, need to step back; iterator.previous(); } } return new BinaryFilePatch(parsedStatus == FileStatus.ADDED ? null : beforeStream.toByteArray(), parsedStatus == FileStatus.DELETED ? null : afterStream.toByteArray()); } catch (Exception e) { throw new PatchSyntaxException(iterator.previousIndex(), e.getMessage()); } } private static void getContent(@NotNull ListIterator<String> iterator, @NotNull ByteArrayOutputStream afterStream, @NotNull String lenFromLiteral) throws EofBinaryPatchSyntaxException, IOException, BinaryEncoder.BinaryPatchException { long afterSize = Long.parseLong(lenFromLiteral); checkNotEOF(iterator); BinaryEncoder.decode(iterator, afterSize, afterStream); } private static void checkNotEOF(@NotNull ListIterator<String> iterator) throws EofBinaryPatchSyntaxException { if (!iterator.hasNext()) throw new EofBinaryPatchSyntaxException(iterator.previousIndex()); } public static class EofBinaryPatchSyntaxException extends PatchSyntaxException { public EofBinaryPatchSyntaxException(int line) { super(line, "Unexpected end of binary patch"); } } }