| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- package info.knacki.pass.git.entities;
- import android.support.annotation.NonNull;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.util.ArrayDeque;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.SortedSet;
- import java.util.TreeSet;
- import java.util.logging.Logger;
- import info.knacki.pass.git.GitSha1;
- import info.knacki.pass.io.CharsetHelper;
- import info.knacki.pass.io.FileUtils;
- public abstract class GitObject implements Comparable<GitObject>, GitPackable {
- GitTree fParent;
- final byte[] fMode;
- final String fName;
- byte[] fSha1;
- @Override
- public int compareTo(@NonNull GitObject gitObject) {
- return fName.toLowerCase().compareTo(gitObject.fName.toLowerCase());
- }
- public static class GitBlob extends GitObject {
- private File fFile;
- private GitBlob(GitTree parent, byte[] mode, String name, byte[] sha1) {
- super(parent, mode, name, sha1);
- fFile = null;
- }
- private GitBlob(GitTree parent, GitBlob copy) {
- this(parent, copy.fMode, copy.fName, copy.fSha1);
- }
- GitBlob(GitTree parent, String filename, File f) {
- this(parent, new byte[] { 49, 48, 48, 54, 52, 52 }, filename, GitSha1.getRawSha1OfFile(f));
- fFile = f;
- }
- @Override
- public eType GetPackableType() {
- return eType.eType_Blob;
- }
- public static byte[] GetFilePack(File f) throws IOException {
- return FileUtils.ReadAllStream(new FileInputStream(f));
- }
- @Override
- public byte[] GetPack() {
- try
- {
- return GetFilePack(fFile);
- }
- catch (FileNotFoundException e) {
- return null;
- }
- catch(IOException t) {
- t.printStackTrace();
- }
- return null;
- }
- }
- public static class GitRawData extends GitBlob {
- private final byte[] fData;
- GitRawData(byte[] sha1, byte[] data) {
- super(null, new byte[] { 49, 48, 48, 54, 52, 52 }, "", sha1);
- fData = data;
- }
- public GitRawData(GitTree parent, byte[] mode, String name, byte[] sha1) {
- super(parent, mode, name, sha1);
- fData = null;
- }
- public GitRawData(GitTree parent, GitBlob emptyBlob, GitRawData prev) {
- super(parent, new byte[] { 49, 48, 48, 54, 52, 52 }, emptyBlob.GetFilename(), prev.GetHash());
- fData = prev.fData;
- }
- @Override
- public eType GetPackableType() {
- return eType.eType_Blob;
- }
- @Override
- public byte[] GetPack() {
- return GetData();
- }
- public byte[] GetData() { return fData; }
- }
- public static class GitTree extends GitObject {
- HashMap<String, GitObject> fItems = null;
- ArrayDeque<String> fItemOrder;
- private GitTree(GitTree parent, byte[] mode, String name, byte[] sha1) {
- super(parent, mode, name, sha1);
- }
- GitTree(GitTree parent, GitTree copy) {
- this(parent, copy.fMode, copy.fName, copy.fSha1);
- Initialize();
- for (Map.Entry<String, GitObject> o: copy.fItems.entrySet()) {
- GitObject src = o.getValue();
- GitObject oCopy = src instanceof GitTree ? new GitTree(this, (GitTree) src) : new GitBlob(this, (GitBlob) src);
- fItems.put(o.getKey(), oCopy);
- }
- for (String i: copy.fItemOrder)
- fItemOrder.push(i);
- }
- GitTree(byte[] sha1) {
- super(null, new byte[] { '4', '0', '0', '0', '0' }, "", sha1);
- }
- private GitTree(GitTree parent, String filename) {
- super(parent, new byte[] { '4', '0', '0', '0', '0' }, filename, null);
- }
- public GitTree(GitTree parent, GitTree content, String filename) {
- this(parent, filename);
- fItems = content.fItems;
- fItemOrder = content.fItemOrder;
- for (GitObject i: fItems.values()) {
- i.SetParent(this);
- }
- }
- public GitTree Initialize() {
- fItems = new HashMap<>();
- fItemOrder = new ArrayDeque<>();
- return this;
- }
- boolean IsInitialized() {
- return null != fItems;
- }
- public GitObject GetObject(String name) {
- return fItems.get(name);
- }
- public GitObject GetObjectFullPath(String path) {
- if ('/' == path.charAt(0))
- path = path.substring(1);
- final int nextSlash = path.indexOf('/');
- final String filename = nextSlash == -1 ? path : (path.substring(0, nextSlash));
- final GitObject obj = GetObject(filename);
- if (obj == null || (obj instanceof GitBlob && nextSlash != -1))
- return null;
- if (nextSlash == -1)
- return obj;
- return ((GitTree) obj).GetObjectFullPath(path.substring(nextSlash +1));
- }
- public GitTree AddItem(GitObject item) {
- fItems.put(item.fName, item);
- fItemOrder.push(item.fName);
- return this;
- }
- public GitTree FindNextNotInitializedTree() {
- if (!IsInitialized())
- return this;
- for (GitObject obj: fItems.values()) {
- if (!(obj instanceof GitTree))
- continue;
- GitTree child = ((GitTree) obj).FindNextNotInitializedTree();
- if (child != null)
- return child;
- }
- return null;
- }
- public Iterable<GitObject> GetObjects() {
- ArrayDeque<GitObject> objects = new ArrayDeque<>();
- for (String i: fItemOrder)
- objects.push(fItems.get(i));
- return objects;
- }
- public Iterable<GitBlob> GetBlobs() {
- SortedSet<GitBlob> objects = new TreeSet<>();
- for (GitObject i: fItems.values())
- if (i instanceof GitBlob)
- objects.add((GitBlob) i);
- return objects;
- }
- public Iterable<GitTree> GetTrees() {
- SortedSet<GitTree> objects = new TreeSet<>();
- for (GitObject i: fItems.values())
- if (i instanceof GitTree)
- objects.add((GitTree) i);
- return objects;
- }
- public String GetPath() {
- if (fParent != null)
- return fParent.GetPath() +GetFilename() +"/";
- return GetFilename() +"/";
- }
- public void SetRealObject(String key, GitObject obj) {
- if (fItems.containsKey(key)) {
- fItems.put(key, obj);
- }
- }
- private void FindAllBlobs(HashMap<String, GitBlob> data) {
- String rootPath = GetPath();
- for (GitBlob i: GetBlobs())
- data.put(rootPath +i.GetFilename(), i);
- for (GitTree i: GetTrees())
- i.FindAllBlobs(data);
- }
- public HashMap<String, GitBlob> FindAllBlobs() {
- HashMap<String, GitBlob> result = new HashMap<>();
- FindAllBlobs(result);
- return result;
- }
- public boolean IsRoot() {
- return fParent == null;
- }
- public GitObject AddItem(String path, File f) {
- if ('/' == path.charAt(0))
- path = path.substring(1);
- final int nextSlash = path.indexOf('/');
- final String filename = nextSlash == -1 ? path : (path.substring(0, nextSlash));
- final GitObject obj = GetObject(filename);
- final GitObject newItem;
- if (obj == null) {
- if (nextSlash != -1) {
- GitTree child = new GitTree(this, filename).Initialize();
- newItem = child.AddItem(path.substring(nextSlash + 1), f);
- fItems.put(filename, child);
- } else {
- newItem = new GitBlob(this, filename, f);
- fItems.put(filename, newItem);
- }
- fItemOrder.push(filename);
- } else if (nextSlash == -1) {
- Remove(filename);
- newItem = new GitBlob(this, filename, f);
- fItems.put(filename, newItem);
- fItemOrder.push(filename);
- } else {
- newItem = ((GitTree) obj).AddItem(path.substring(nextSlash + 1), f);
- }
- fSha1 = null;
- return newItem;
- }
- public GitTree Remove(String filename) {
- fItems.remove(filename);
- fItemOrder.remove(filename);
- fSha1 = null;
- return this;
- }
- public void Fill(byte[] data) {
- int i = 0;
- while (i < data.length) {
- byte[] mode = null;
- int len;
- for (len =0; i +len <data.length && len < 8; ++len) {
- if (data[i + len] == ' ') {
- mode = new byte[len];
- System.arraycopy(data, i, mode, 0, len);
- i += len + 1;
- break;
- }
- }
- if (mode == null)
- break;
- len =0;
- while (i +len < data.length && data[i +len] != 0)
- ++len;
- byte[] filenameBytes = new byte[len];
- System.arraycopy(data, i, filenameBytes, 0, len);
- i += len +1;
- if (i +20 > data.length)
- break;
- byte []sha1 = new byte[20];
- System.arraycopy(data, i, sha1, 0, 20);
- i += 20;
- AddItem(GitObject.factory(this, mode, CharsetHelper.ByteArrayToString(filenameBytes), sha1));
- }
- }
- @Override
- public eType GetPackableType() {
- return eType.eType_Tree;
- }
- @Override
- public byte[] GetPack() {
- try {
- ByteArrayOutputStream str = new ByteArrayOutputStream();
- for (GitObject go : GetObjects()) {
- str.write((go.GetMode() + ' ').getBytes());
- if (go.fName.equals("Aa") || "Oo".equals(go.fName))
- Logger.getLogger(GitObject.class.getName()).severe("out file in tree " +go.GetGitPath() +"$" + GitSha1.BytesToString(go.GetHash()));
- str.write(go.GetFilename().getBytes());
- str.write(new byte[]{0});
- str.write(go.GetHash());
- }
- return str.toByteArray();
- }
- catch (IOException e) {
- return null;
- }
- }
- @Override
- public byte[] GetHash() {
- if (null != fSha1)
- return fSha1;
- return fSha1 = GitSha1.getRawSha1OfPackable(this);
- }
- }
- private GitObject(GitTree parent, byte[] mode, String name, byte[] sha1) {
- fParent = parent;
- fMode = mode;
- fName = name;
- fSha1 = sha1;
- }
- public static GitObject factory(GitTree parent, byte[] mode, String name, byte[] sha1) {
- if (mode[0] == '4') {
- return new GitTree(parent, mode, name, sha1);
- }
- return new GitRawData(parent, mode, name, sha1);
- }
- public byte[] GetHash() {
- return fSha1;
- }
- public String GetFilename() {
- return fName;
- }
- public String GetGitPath() {
- StringBuilder sb = new StringBuilder();
- GitTree parent = fParent;
- sb.insert(0, fName);
- while (parent != null) {
- sb.insert(0, parent.fName + "/");
- parent = parent.fParent;
- }
- return sb.toString();
- }
- public GitTree GetParent() {
- return fParent;
- }
- private void SetParent(GitTree t) { fParent = t; }
- public String GetMode() {
- return new String(fMode);
- }
- public int GetDepth() {
- return fParent == null ? 1 : fParent.GetDepth() +1;
- }
- }
|