+/* skip SFX header */
+int
+seek_lha_header(fp)
+ FILE *fp;
+{
+ unsigned char buffer[64 * 1024]; /* max seek size */
+ unsigned char *p;
+ int n;
+
+ n = fread(buffer, 1, sizeof(buffer), fp);
+
+ for (p = buffer; p < buffer + n; p++) {
+ if (! (p[I_METHOD]=='-' &&
+ (p[I_METHOD+1]=='l' || p[I_METHOD+1]=='p') &&
+ p[I_METHOD+4]=='-'))
+ continue;
+ /* found "-[lp]??-" keyword (as METHOD type string) */
+
+ /* level 0 or 1 header */
+ if ((p[I_HEADER_LEVEL] == 0 || p[I_HEADER_LEVEL] == 1)
+ && p[I_HEADER_SIZE] > 20
+ && p[I_HEADER_CHECKSUM] == calc_sum(p+2, p[I_HEADER_SIZE])) {
+ if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
+ fatal_error("cannot seek header");
+ return 0;
+ }
+
+ /* level 2 header */
+ if (p[I_HEADER_LEVEL] == 2
+ && p[I_HEADER_SIZE] >= 24
+ && p[I_ATTRIBUTE] == 0x20) {
+ if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
+ fatal_error("cannot seek header");
+ return 0;
+ }
+ }
+
+ if (fseeko(fp, -n, SEEK_CUR) == -1)
+ fatal_error("cannot seek header");
+ return -1;
+}
+
+
+/* remove leading `xxxx/..' */
+static char *
+remove_leading_dots(char *path)
+{
+ char *first = path;
+ char *ptr = 0;
+
+ if (strcmp(first, "..") == 0) {
+ warning("Removing leading `..' from member name.");
+ return first+1; /* change to "." */
+ }
+
+ if (strstr(first, "..") == 0)
+ return first;
+
+ while (path && *path) {
+
+ if (strcmp(path, "..") == 0)
+ ptr = path = path+2;
+ else if (strncmp(path, "../", 3) == 0)
+ ptr = path = path+3;
+ else
+ path = strchr(path, '/');
+
+ if (path && *path == '/') {
+ path++;
+ }
+ }
+
+ if (ptr) {
+ warning("Removing leading `%.*s' from member name.", ptr-first, first);
+ return ptr;
+ }
+
+ return first;
+}
+
+static int
+copy_path_element(char *dst, const char *src, int size)
+{
+ int i;
+
+ if (size < 1) return 0;
+
+ for (i = 0; i < size; i++) {
+ dst[i] = src[i];
+ if (dst[i] == '\0')
+ return i;
+ if (dst[i] == '/') {
+ dst[++i] = 0;
+ return i;
+ }
+ }
+
+ dst[--i] = 0;
+
+ return i;
+}
+
+/*
+ canonicalize path
+
+ remove leading "xxx/../"
+ remove "./", "././", "././ ... ./"
+ remove duplicated "/"
+*/
+static int
+canon_path(char *newpath, char *path, size_t size)
+{
+ char *p = newpath;
+
+ path = remove_leading_dots(path);
+
+ while (*path) {
+ if (path[0] == '.' && path[1] == '/')
+ path += 2;
+ else {
+ int len;
+ len = copy_path_element(newpath, path, size);
+
+ path += len;
+ newpath += len;
+ size -= len;
+ if (size <= 1)
+ break;
+ }
+
+ /* remove duplicated '/' */
+ while (*path == '/') path++;
+ }
+
+ /* When newpath is empty, set "." */
+ if (newpath == p) {
+ strcpy(newpath, ".");
+ newpath++;
+ }
+
+ return newpath - p; /* string length */
+}
+