1 /* -*- C++ -*-
2  *
3  *  NsaReader.cpp - Reader from a NSA archive
4  *
5  *  Copyright (c) 2001-2019 Ogapee. All rights reserved.
6  *
7  *  ogapee@aqua.dti2.ne.jp
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include "NsaReader.h"
25 #include <string.h>
26 
NsaReader(unsigned int nsa_offset,char * path,int archive_type,const unsigned char * key_table)27 NsaReader::NsaReader( unsigned int nsa_offset, char *path, int archive_type, const unsigned char *key_table )
28         :SarReader( path, key_table )
29 {
30     sar_flag = true;
31     this->nsa_offset = nsa_offset;
32     this->archive_type = archive_type;
33     num_of_nsa_archives[0] = 0;
34     num_of_nsa_archives[1] = 0;
35     num_of_ns2_archives = 0;
36 
37     if (key_table)
38         nsa_archive_ext = "___";
39     else
40         nsa_archive_ext = "nsa";
41 
42     ns2_archive_ext = "ns2";
43 }
44 
~NsaReader()45 NsaReader::~NsaReader()
46 {
47 }
48 
open(const char * nsa_path)49 int NsaReader::open( const char *nsa_path )
50 {
51     bool archive_found = false;
52     char archive_name[256];
53 
54     if (!SarReader::open("arc.sar")) return 0;
55 
56     sar_flag = false;
57 
58     if (archive_type & ARCHIVE_TYPE_NS2){
59         for (int i=0; i<MAX_NS2_ARCHIVE; i++){
60             sprintf(archive_name, "%s%02d.%s", nsa_path?nsa_path:"", i, ns2_archive_ext);
61             if ((archive_info_ns2[i].file_handle = fopen(archive_name, "rb")) == NULL) break;
62 
63             ArchiveInfo *ai = &archive_info_ns2[i];
64             archive_found = true;
65             ai->file_name = new char[strlen(archive_name)+1];
66             memcpy(ai->file_name, archive_name, strlen(archive_name)+1);
67             readArchive(ai, ARCHIVE_TYPE_NS2, nsa_offset);
68             num_of_ns2_archives = i+1;
69         }
70     }
71 
72     if (num_of_ns2_archives ==0 && archive_type & ARCHIVE_TYPE_NSA){
73         for (int k=0; k<2; k++){
74             for (int i=-1; i<MAX_EXTRA_ARCHIVE; i++){
75                 ArchiveInfo *ai;
76 
77                 if (i == -1){
78                     sprintf(archive_name, "%s%sarc.%s", nsa_path?nsa_path:"", k==0?"patch/":"", nsa_archive_ext);
79                     ai = k==0?(&archive_info_patch):(&archive_info);
80                 }
81                 else{
82                     sprintf(archive_name, "%s%sarc%d.%s", nsa_path?nsa_path:"", k==0?"patch/":"", i+1, nsa_archive_ext);
83                     ai = &archive_info2[k][i];
84                 }
85 
86                 if ((ai->file_handle = fopen(archive_name, "rb")) == NULL) break;
87 
88                 archive_found = true;
89                 ai->file_name = new char[strlen(archive_name)+1];
90                 memcpy(ai->file_name, archive_name, strlen(archive_name)+1);
91                 readArchive(ai, ARCHIVE_TYPE_NSA, nsa_offset);
92                 num_of_nsa_archives[k] = i+1;
93             }
94         }
95     }
96 
97     if (!archive_found) return -1;
98 
99     return 0;
100 }
101 
openForConvert(char * nsa_name,int archive_type,unsigned int nsa_offset)102 int NsaReader::openForConvert( char *nsa_name, int archive_type, unsigned int nsa_offset )
103 {
104     sar_flag = false;
105     if ( ( archive_info.file_handle = ::fopen( nsa_name, "rb" ) ) == NULL ){
106         fprintf( stderr, "can't open file %s\n", nsa_name );
107         return -1;
108     }
109 
110     readArchive( &archive_info, archive_type, nsa_offset );
111 
112     return 0;
113 }
114 
writeHeader(FILE * fp,int archive_type,int nsa_offset)115 int NsaReader::writeHeader( FILE *fp, int archive_type, int nsa_offset )
116 {
117     ArchiveInfo *ai = &archive_info;
118     return writeHeaderSub( ai, fp, archive_type, nsa_offset );
119 }
120 
putFile(FILE * fp,int no,size_t offset,size_t length,size_t original_length,int compression_type,bool modified_flag,unsigned char * buffer)121 size_t NsaReader::putFile( FILE *fp, int no, size_t offset, size_t length, size_t original_length, int compression_type, bool modified_flag, unsigned char *buffer )
122 {
123     ArchiveInfo *ai = &archive_info;
124     return putFileSub( ai, fp, no, offset, length, original_length , compression_type, modified_flag, buffer );
125 }
126 
getArchiveName() const127 const char *NsaReader::getArchiveName() const
128 {
129     return "nsa";
130 }
131 
getNumFiles()132 int NsaReader::getNumFiles()
133 {
134     int total = 0;
135 
136     ArchiveInfo* ai[2] = {&archive_info_patch, &archive_info};
137     for (int k=0; k<2; k++){
138         total += ai[k]->num_of_files;
139         for (int i=0; i<num_of_nsa_archives[k]; i++)
140             total += archive_info2[k][i].num_of_files;
141     }
142 
143     for (int i=0; i<num_of_ns2_archives; i++)
144         total += archive_info_ns2[i].num_of_files;
145 
146     return total;
147 }
148 
getFileLengthSub(ArchiveInfo * ai,const char * file_name)149 size_t NsaReader::getFileLengthSub( ArchiveInfo *ai, const char *file_name )
150 {
151     unsigned int i = getIndexFromFile( ai, file_name );
152 
153     if ( i == ai->num_of_files ) return 0;
154 
155     if ( ai->fi_list[i].original_length != 0 )
156         return ai->fi_list[i].original_length;
157 
158     int type = ai->fi_list[i].compression_type;
159     if ( type == NO_COMPRESSION )
160         type = getRegisteredCompressionType( file_name );
161     if ( type == NBZ_COMPRESSION || type == SPB_COMPRESSION ) {
162         ai->fi_list[i].original_length = getDecompressedFileLength( type, ai->file_handle, ai->fi_list[i].offset );
163     }
164 
165     return ai->fi_list[i].original_length;
166 }
167 
getFileLength(const char * file_name)168 size_t NsaReader::getFileLength(const char *file_name)
169 {
170     if (sar_flag) return SarReader::getFileLength(file_name);
171 
172     size_t ret;
173 
174     if ((ret = DirectReader::getFileLength(file_name))) return ret;
175 
176     for (int i=0; i<num_of_ns2_archives; i++)
177         if ((ret = getFileLengthSub(&archive_info_ns2[i], file_name))) return ret;
178 
179     ArchiveInfo* ai[2] = {&archive_info_patch, &archive_info};
180     for (int k=0; k<2; k++){
181         if ((ret = getFileLengthSub(ai[k], file_name))) return ret;
182 
183         for (int i=0; i<num_of_nsa_archives[k]; i++)
184             if ((ret = getFileLengthSub(&archive_info2[k][i], file_name))) return ret;
185     }
186 
187     return 0;
188 }
189 
getFile(const char * file_name,unsigned char * buffer,int * location)190 size_t NsaReader::getFile(const char *file_name, unsigned char *buffer, int *location)
191 {
192     size_t ret;
193 
194     if (sar_flag) return SarReader::getFile( file_name, buffer, location );
195 
196     if ((ret = DirectReader::getFile(file_name, buffer, location))) return ret;
197 
198     for (int i=0; i<num_of_ns2_archives; i++){
199         if ((ret = getFileSub(&archive_info_ns2[i], file_name, buffer))){
200             if (location) *location = ARCHIVE_TYPE_NS2;
201             return ret;
202         }
203     }
204 
205     ArchiveInfo* ai[2] = {&archive_info_patch, &archive_info};
206     for (int k=0; k<2; k++){
207         if ((ret = getFileSub(ai[k], file_name, buffer))){
208             if (location) *location = ARCHIVE_TYPE_NSA;
209             return ret;
210         }
211 
212         for (int i=0; i<num_of_nsa_archives[k]; i++){
213             if ((ret = getFileSub(&archive_info2[k][i], file_name, buffer))){
214                 if (location) *location = ARCHIVE_TYPE_NSA;
215                 return ret;
216             }
217         }
218     }
219 
220     return 0;
221 }
222 
getFileByIndex(unsigned int index)223 NsaReader::FileInfo NsaReader::getFileByIndex(unsigned int index)
224 {
225     for (int i=0; i<num_of_ns2_archives; i++){
226         if (index < archive_info_ns2[i].num_of_files) return archive_info_ns2[i].fi_list[index];
227         index -= archive_info_ns2[i].num_of_files;
228     }
229 
230     ArchiveInfo* ai[2] = {&archive_info_patch, &archive_info};
231     for (int k=0; k<2; k++){
232         if (index < ai[k]->num_of_files) return archive_info.fi_list[index];
233         index -= ai[k]->num_of_files;
234 
235         for (int i=0; i<num_of_nsa_archives[k]; i++){
236             if (index < archive_info2[k][i].num_of_files) return archive_info2[k][i].fi_list[index];
237             index -= archive_info2[k][i].num_of_files;
238         }
239     }
240 
241     fprintf( stderr, "NsaReader::getFileByIndex  Index %d is out of range\n", index );
242 
243     return archive_info.fi_list[0];
244 }
245