/* https://github.com/BlackOverlord666/mslinks Copyright (c) 2015 Dmitrii Shamrikov Licensed under the WTFPL You may obtain a copy of the License at http://www.wtfpl.net/about/ 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. */ package mslinks; import io.ByteReader; import io.ByteWriter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import mslinks.data.*; public class LinkInfo implements Serializable { private LinkInfoFlags lif; private VolumeID vid; private String localBasePath; private CNRLink cnrlink; private String commonPathSuffix; public LinkInfo() { lif = new LinkInfoFlags(0); } public LinkInfo(ByteReader data) throws IOException, ShellLinkException { int pos = data.getPosition(); int size = (int)data.read4bytes(); int hsize = (int)data.read4bytes(); lif = new LinkInfoFlags(data); int vidoffset = (int)data.read4bytes(); int lbpoffset = (int)data.read4bytes(); int cnrloffset = (int)data.read4bytes(); int cpsoffset = (int)data.read4bytes(); int lbpoffset_u = 0, cpfoffset_u = 0; if (hsize >= 0x24) { lbpoffset_u = (int)data.read4bytes(); cpfoffset_u = (int)data.read4bytes(); } if (lif.hasVolumeIDAndLocalBasePath()) { data.seek(pos + vidoffset - data.getPosition()); vid = new VolumeID(data); data.seek(pos + lbpoffset - data.getPosition()); localBasePath = data.readString(pos + size - data.getPosition()); } if (lif.hasCommonNetworkRelativeLinkAndPathSuffix()) { data.seek(pos + cnrloffset - data.getPosition()); cnrlink = new CNRLink(data); data.seek(pos + cpsoffset - data.getPosition()); commonPathSuffix = data.readString(pos + size - data.getPosition()); } if (lif.hasVolumeIDAndLocalBasePath() && lbpoffset_u != 0) { data.seek(pos + lbpoffset_u - data.getPosition()); localBasePath = data.readUnicodeString((pos + size - data.getPosition())>>1); } if (lif.hasCommonNetworkRelativeLinkAndPathSuffix() && cpfoffset_u != 0) { data.seek(pos + cpfoffset_u - data.getPosition()); commonPathSuffix = data.readUnicodeString((pos + size - data.getPosition())>>1); } data.seek(pos + size - data.getPosition()); } public void serialize(ByteWriter bw) throws IOException { int pos = bw.getPosition(); int hsize = 28; CharsetEncoder ce = Charset.defaultCharset().newEncoder(); if (localBasePath != null && !ce.canEncode(localBasePath) || commonPathSuffix != null && !ce.canEncode(commonPathSuffix)) hsize += 8; byte[] vid_b = null, localBasePath_b = null, cnrlink_b = null, commonPathSuffix_b = null; if (lif.hasVolumeIDAndLocalBasePath()) { vid_b = toByteArray(vid); localBasePath_b = localBasePath.getBytes(); commonPathSuffix_b = new byte[0]; } if (lif.hasCommonNetworkRelativeLinkAndPathSuffix()) { cnrlink_b = toByteArray(cnrlink); commonPathSuffix_b = commonPathSuffix.getBytes(); } int size = hsize + (vid_b == null? 0 : vid_b.length) + (localBasePath_b == null? 0 : localBasePath_b.length + 1) + (cnrlink_b == null? 0 : cnrlink_b.length) + commonPathSuffix_b.length + 1; if (hsize > 28) { if (lif.hasVolumeIDAndLocalBasePath()) { size += localBasePath.length() * 2 + 2; size += 1; } if (lif.hasCommonNetworkRelativeLinkAndPathSuffix()) size += commonPathSuffix.length() * 2; size += 2; } bw.write4bytes(size); bw.write4bytes(hsize); lif.serialize(bw); int off = hsize; if (lif.hasVolumeIDAndLocalBasePath()) { bw.write4bytes(off); // volumeid offset off += vid_b.length; bw.write4bytes(off); // localBasePath offset off += localBasePath_b.length + 1; } else { bw.write4bytes(0); // volumeid offset bw.write4bytes(0); // localBasePath offset } if (lif.hasCommonNetworkRelativeLinkAndPathSuffix()) { bw.write4bytes(off); // CommonNetworkRelativeLink offset off += cnrlink_b.length; bw.write4bytes(off); // commonPathSuffix off += commonPathSuffix_b.length + 1; } else { bw.write4bytes(0); // CommonNetworkRelativeLinkOffset bw.write4bytes(size - (hsize > 28 ? 4 : 1)); // fake commonPathSuffix offset } if (hsize > 28) { if (lif.hasVolumeIDAndLocalBasePath()) { bw.write4bytes(off); // LocalBasePathOffsetUnicode off += localBasePath.length() * 2 + 2; bw.write4bytes(size - 2); // fake CommonPathSuffixUnicode offset } else { bw.write4bytes(0); bw.write4bytes(off); // CommonPathSuffixUnicode offset off += commonPathSuffix.length() * 2 + 2; } } if (lif.hasVolumeIDAndLocalBasePath()) { bw.writeBytes(vid_b); bw.writeBytes(localBasePath_b); bw.write(0); } if (lif.hasCommonNetworkRelativeLinkAndPathSuffix()) { bw.writeBytes(cnrlink_b); bw.writeBytes(commonPathSuffix_b); bw.write(0); } if (hsize > 28) { if (lif.hasVolumeIDAndLocalBasePath()) { for (int i=0; i<localBasePath.length(); i++) bw.write2bytes(localBasePath.charAt(i)); bw.write2bytes(0); } if (lif.hasCommonNetworkRelativeLinkAndPathSuffix()) { for (int i=0; i<commonPathSuffix.length(); i++) bw.write2bytes(commonPathSuffix.charAt(i)); bw.write2bytes(0); } } while (bw.getPosition() < pos + size) bw.write(0); } private byte[] toByteArray(Serializable o) throws IOException { ByteArrayOutputStream arr = new ByteArrayOutputStream(); ByteWriter bt = new ByteWriter(arr); o.serialize(bt); return arr.toByteArray(); } public VolumeID getVolumeID() { return vid; } /** * Creates VolumeID and LocalBasePath that is empty string */ public VolumeID createVolumeID() { vid = new VolumeID(); localBasePath = ""; lif.setVolumeIDAndLocalBasePath(); return vid; } public String getLocalBasePath() { return localBasePath; } /** * Set LocalBasePath and creates new VolumeID (if it not exists) * If s is null takes no effect */ public LinkInfo setLocalBasePath(String s) { if (s == null) return this; localBasePath = s; if (vid == null) vid = new VolumeID(); lif.setVolumeIDAndLocalBasePath(); return this; } public CNRLink getCommonNetworkRelativeLink() { return cnrlink; } /** * Creates CommonNetworkRelativeLink and CommonPathSuffix that is empty string */ public CNRLink createCommonNetworkRelativeLink() { cnrlink = new CNRLink(); commonPathSuffix = ""; lif.setCommonNetworkRelativeLinkAndPathSuffix(); return cnrlink; } public String getCommonPathSuffix() { return commonPathSuffix; } /** * Set CommonPathSuffix and creates new CommonNetworkRelativeLink (if it not exists) * If s is null takes no effect */ public LinkInfo setCommonPathSuffix(String s) { if (s == null) return this; commonPathSuffix = s; if (cnrlink == null) cnrlink = new CNRLink(); lif.setCommonNetworkRelativeLinkAndPathSuffix(); return this; } }