1+ package io .opentdf .platform .sdk ;
2+
3+ import java .nio .ByteBuffer ;
4+ import java .nio .ByteOrder ;
5+ import java .nio .charset .StandardCharsets ;
6+
7+ public class ZipReader {
8+ private static final int END_OF_CENTRAL_DIRECTORY_SIGNATURE = 0x06054b50 ;
9+ private static final int ZIP64_END_OF_CENTRAL_DIRECTORY_SIGNATURE = 0x06064b50 ;
10+ private static final int ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIGNATURE = 0x07064b50 ;
11+ private static final int CENTRAL_DIRECTORY_LOCATOR_SIGNATURE = 0x02014b50 ;
12+ private static final int LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50 ;
13+ private static final int ZIP64_MAGICVAL = 0xFFFFFFFF ;
14+ private static final int ZIP64_EXTID = 0x0001 ;
15+
16+ private int numEntries ;
17+ private short fileNameLength ;
18+ private short extraFieldLength ;
19+ private long offsetToStartOfCentralDirectory ;
20+ private long relativeOffsetEndOfZip64EndOfCentralDirectory ;
21+
22+ public void readEndOfCentralDirectory (ByteBuffer buffer ) throws Exception {
23+ buffer .order (ByteOrder .LITTLE_ENDIAN );
24+ long fileSize = buffer .capacity ();
25+ long pointer = fileSize - 22 ; // 22 is the minimum size of the EOCDR
26+
27+ // Search for the EOCDR from the end of the file
28+ while (pointer >= 0 ) {
29+ buffer .position ((int )pointer );
30+ int signature = buffer .getInt ();
31+ if (signature == END_OF_CENTRAL_DIRECTORY_SIGNATURE ) {
32+ System .out .println ("Found End of Central Directory Record" );
33+ break ;
34+ }
35+ pointer --;
36+ }
37+
38+ if (pointer < 0 ) {
39+ throw new Exception ("Invalid tdf file" );
40+ }
41+
42+ // Read the EOCDR
43+ short diskNumber = buffer .getShort ();
44+ short centralDirectoryDiskNumber = buffer .getShort ();
45+ short numEntriesThisDisk = buffer .getShort ();
46+ numEntries = buffer .getShort ();
47+ int centralDirectorySize = buffer .getInt ();
48+ offsetToStartOfCentralDirectory = buffer .getInt ();
49+ short commentLength = buffer .getShort ();
50+
51+ // buffer's position at the start of the Central Directory
52+ boolean isZip64 = false ;
53+ if (offsetToStartOfCentralDirectory != ZIP64_MAGICVAL ) {
54+ //buffer.position((int)offsetToStartOfCentralDirectory);
55+ } else {
56+ isZip64 = true ;
57+ long index = fileSize - (22 + 20 ); // 22 is the size of the EOCDR and 20 is the size of the Zip64 EOCDR
58+ buffer .position ((int )index );
59+ readZip64EndOfCentralDirectoryLocator (buffer );
60+ index = fileSize - (22 + 20 + 56 ); // 56 is the size of the Zip64 EOCDR
61+ buffer .position ((int )index );
62+ readZip64EndOfCentralDirectoryRecord (buffer );
63+ //buffer.position((int)offsetToStartOfCentralDirectory);
64+ }
65+ // buffer.position(centralDirectoryOffset);
66+ }
67+
68+ private void readZip64EndOfCentralDirectoryLocator (ByteBuffer buffer ) {
69+ int signature = buffer .getInt () ;
70+ if (signature != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIGNATURE ) {
71+ throw new RuntimeException ("Invalid Zip64 End of Central Directory Record Signature" );
72+ }
73+ int numberOfDiskWithZip64End = buffer .getInt ();
74+ relativeOffsetEndOfZip64EndOfCentralDirectory = buffer .getLong ();
75+ int totalNumberOfDisks = buffer .getInt ();
76+ }
77+
78+ private void readZip64EndOfCentralDirectoryRecord (ByteBuffer buffer ) {
79+ int signature = buffer .getInt () ;
80+ if (signature != ZIP64_END_OF_CENTRAL_DIRECTORY_SIGNATURE ) {
81+ throw new RuntimeException ("Invalid Zip64 End of Central Directory Record " );
82+ }
83+ long sizeOfZip64EndOfCentralDirectoryRecord = buffer .getLong ();
84+ short versionMadeBy = buffer .getShort ();
85+ short versionNeededToExtract = buffer .getShort ();
86+ int diskNumber = buffer .getInt ();
87+ int diskWithCentralDirectory = buffer .getInt ();
88+ long numEntriesOnThisDisk = buffer .getLong ();
89+ numEntries = (int )buffer .getLong ();
90+ long centralDirectorySize = buffer .getLong ();
91+ offsetToStartOfCentralDirectory = buffer .getLong ();
92+ }
93+
94+ public int getNumEntries () {
95+ return numEntries ;
96+ }
97+
98+ public short getFileNameLength () {
99+ return fileNameLength ;
100+ }
101+
102+ public short getExtraFieldLength () {
103+ return extraFieldLength ;
104+ }
105+
106+ public long getCDOffset () {
107+ return offsetToStartOfCentralDirectory ;
108+ }
109+
110+ public long readCentralDirectoryFileHeader (ByteBuffer buffer ) {
111+ System .out .println ("Buffer position: " + buffer .position ());
112+ int signature = buffer .getInt ();
113+ if (signature != CENTRAL_DIRECTORY_LOCATOR_SIGNATURE ) {
114+ throw new RuntimeException ("Invalid Central Directory File Header Signature" );
115+ }
116+ short versionMadeBy = buffer .getShort ();
117+ short versionNeededToExtract = buffer .getShort ();
118+ short generalPurposeBitFlag = buffer .getShort ();
119+ short compressionMethod = buffer .getShort ();
120+ short lastModFileTime = buffer .getShort ();
121+ short lastModFileDate = buffer .getShort ();
122+ int crc32 = buffer .getInt ();
123+ int compressedSize = buffer .getInt ();
124+ int uncompressedSize = buffer .getInt ();
125+ fileNameLength = buffer .getShort ();
126+ extraFieldLength = buffer .getShort ();
127+ short fileCommentLength = buffer .getShort ();
128+ short diskNumberStart = buffer .getShort ();
129+ short internalFileAttributes = buffer .getShort ();
130+ int externalFileAttributes = buffer .getInt ();
131+ long relativeOffsetOfLocalHeader = buffer .getInt () ;
132+
133+ byte [] fileName = new byte [fileNameLength ];
134+ buffer .get (fileName );
135+ String fileNameString = new String (fileName , StandardCharsets .UTF_8 );
136+ ////
137+ if (compressedSize == ZIP64_MAGICVAL || uncompressedSize == ZIP64_MAGICVAL || relativeOffsetOfLocalHeader == ZIP64_MAGICVAL ) {
138+ // Parse the extra field
139+ for (int i = 0 ; i < extraFieldLength ; ) {
140+ int headerId = buffer .getShort ();
141+ int dataSize = buffer .getShort ();
142+ i += 4 ;
143+
144+ if (headerId == ZIP64_EXTID ) {
145+ if (compressedSize == ZIP64_MAGICVAL ) {
146+ compressedSize = (int )buffer .getLong ();
147+ i += 8 ;
148+ }
149+ if (uncompressedSize == ZIP64_MAGICVAL ) {
150+ uncompressedSize = (int )buffer .getLong ();
151+ i += 8 ;
152+ }
153+ if (relativeOffsetOfLocalHeader == ZIP64_MAGICVAL ) {
154+ relativeOffsetOfLocalHeader = buffer .getLong ();
155+ i += 8 ;
156+ }
157+ } else {
158+ // Skip other extra fields
159+ buffer .position (buffer .position () + dataSize );
160+ i += dataSize ;
161+ }
162+ }
163+ }
164+ ////
165+ byte [] extraField = new byte [extraFieldLength ];
166+ buffer .get (extraField );
167+
168+ byte [] fileComment = new byte [fileCommentLength ];
169+ buffer .get (fileComment );
170+ String fileCommentString = new String (fileComment , StandardCharsets .UTF_8 );
171+ return relativeOffsetOfLocalHeader ;
172+ }
173+
174+ public void readLocalFileHeader (ByteBuffer buffer ) {
175+ int signature = buffer .getInt ();
176+ if (signature != LOCAL_FILE_HEADER_SIGNATURE ) {
177+ throw new RuntimeException ("Invalid Local File Header Signature" );
178+ }
179+ short versionNeededToExtract = buffer .getShort ();
180+ short generalPurposeBitFlag = buffer .getShort ();
181+ short compressionMethod = buffer .getShort ();
182+ short lastModFileTime = buffer .getShort ();
183+ short lastModFileDate = buffer .getShort ();
184+ int crc32 = buffer .getInt ();
185+ int compressedSize = buffer .getInt ();
186+ int uncompressedSize = buffer .getInt ();
187+ short fileNameLength = buffer .getShort ();
188+ short extraFieldLength = buffer .getShort ();
189+
190+ byte [] fileName = new byte [fileNameLength ];
191+ buffer .get (fileName );
192+ String fileNameString = new String (fileName , StandardCharsets .UTF_8 );
193+ System .out .println ("File name: " + fileNameString );
194+
195+ byte [] extraField = new byte [extraFieldLength ];
196+ buffer .get (extraField );
197+
198+ /*byte[] fileData = new byte[compressedSize];
199+ buffer.get(fileData);
200+
201+ if (compressionMethod == 0) {
202+ String fileContent = new String(fileData, StandardCharsets.UTF_8);
203+ System.out.println("File content: " + fileContent);
204+ } else {
205+ System.out.println("File is compressed, need to decompress it first");
206+ }*/
207+ }
208+ }
0 commit comments